Best Python code snippet using playwright-python
test_acceptparse.py
Source:test_acceptparse.py
...2727 {'UTF-7': 0.5, 'unicode-1-1': 0.0, 'UTF-8': 1.0},2728 'UTF-8, UTF-7;q=0.5, unicode-1-1;q=0',2729 ),2730 ])2731 def test___add___valid_header_value(self, value, value_as_header):2732 result = AcceptCharsetInvalidHeader(header_value='') + value2733 assert isinstance(result, AcceptCharsetValidHeader)2734 assert result.header_value == value_as_header2735 def test___add___other_type_valid_header_value(self):2736 class Other(object):2737 def __str__(self):2738 return 'UTF-7;q=0.5, unicode-1-1;q=0, UTF-8'2739 right_operand = Other()2740 result = AcceptCharsetInvalidHeader(header_value='') + right_operand2741 assert isinstance(result, AcceptCharsetValidHeader)2742 assert result.header_value == str(right_operand)2743 def test___add___AcceptCharsetValidHeader(self):2744 right_operand = AcceptCharsetValidHeader(2745 header_value=', ,utf-7;q=0, \tutf-8;q=1,',2746 )2747 result = AcceptCharsetInvalidHeader(header_value='') + right_operand2748 assert isinstance(result, AcceptCharsetValidHeader)2749 assert result.header_value == right_operand.header_value2750 assert result is not right_operand2751 def test___add___AcceptCharsetNoHeader(self):2752 right_operand = AcceptCharsetNoHeader()2753 result = AcceptCharsetInvalidHeader(header_value='') + right_operand2754 assert isinstance(result, AcceptCharsetNoHeader)2755 assert result is not right_operand2756 def test___add___AcceptCharsetInvalidHeader(self):2757 result = AcceptCharsetInvalidHeader(header_value='') + \2758 AcceptCharsetInvalidHeader(header_value='utf/8')2759 assert isinstance(result, AcceptCharsetNoHeader)2760 def test___bool__(self):2761 instance = AcceptCharsetInvalidHeader(header_value='')2762 returned = bool(instance)2763 assert returned is False2764 @pytest.mark.filterwarnings(IGNORE_CONTAINS)2765 def test___contains__(self):2766 instance = AcceptCharsetInvalidHeader(header_value='')2767 returned = ('char-set' in instance)2768 assert returned is True2769 @pytest.mark.filterwarnings(IGNORE_ITER)2770 def test___iter__(self):2771 instance = AcceptCharsetInvalidHeader(header_value='')2772 returned = list(instance)2773 assert returned == []2774 def test___radd___None(self):2775 result = None + AcceptCharsetInvalidHeader(header_value='')2776 assert isinstance(result, AcceptCharsetNoHeader)2777 @pytest.mark.parametrize('left_operand', [2778 '',2779 [],2780 (),2781 {},2782 'UTF/8',2783 ['UTF/8'],2784 ('UTF/8',),2785 {'UTF/8': 1.0},2786 ])2787 def test___radd___invalid_value(self, left_operand):2788 result = left_operand + AcceptCharsetInvalidHeader(header_value='')2789 assert isinstance(result, AcceptCharsetNoHeader)2790 @pytest.mark.parametrize('str_', ['', 'UTF/8'])2791 def test___radd___other_type_with_invalid___str__(self, str_):2792 class Other(object):2793 def __str__(self):2794 return str_2795 result = Other() + AcceptCharsetInvalidHeader(header_value='')2796 assert isinstance(result, AcceptCharsetNoHeader)2797 @pytest.mark.parametrize('value, value_as_header', [2798 (2799 'UTF-7;q=0.5, unicode-1-1;q=0, UTF-8',2800 'UTF-7;q=0.5, unicode-1-1;q=0, UTF-8',2801 ),2802 (2803 [('UTF-7', 0.5), ('unicode-1-1', 0.0), 'UTF-8'],2804 'UTF-7;q=0.5, unicode-1-1;q=0, UTF-8',2805 ),2806 (2807 (('UTF-7', 0.5), ('unicode-1-1', 0.0), 'UTF-8'),2808 'UTF-7;q=0.5, unicode-1-1;q=0, UTF-8',2809 ),2810 (2811 {'UTF-7': 0.5, 'unicode-1-1': 0.0, 'UTF-8': 1.0},2812 'UTF-8, UTF-7;q=0.5, unicode-1-1;q=0',2813 ),2814 ])2815 def test___radd___valid_header_value(self, value, value_as_header):2816 result = value + AcceptCharsetInvalidHeader(header_value='')2817 assert isinstance(result, AcceptCharsetValidHeader)2818 assert result.header_value == value_as_header2819 def test___radd___other_type_valid_header_value(self):2820 class Other(object):2821 def __str__(self):2822 return 'UTF-7;q=0.5, unicode-1-1;q=0, UTF-8'2823 left_operand = Other()2824 result = left_operand + AcceptCharsetInvalidHeader(header_value='')2825 assert isinstance(result, AcceptCharsetValidHeader)2826 assert result.header_value == str(left_operand)2827 def test___repr__(self):2828 instance = AcceptCharsetInvalidHeader(header_value='\x00')2829 assert repr(instance) == '<AcceptCharsetInvalidHeader>'2830 def test___str__(self):2831 instance = AcceptCharsetInvalidHeader(header_value='')2832 assert str(instance) == '<invalid header value>'2833 def test_acceptable_offers(self):2834 instance = AcceptCharsetInvalidHeader(header_value='')2835 returned = instance.acceptable_offers(2836 offers=['utf-8', 'utf-7', 'unicode-1-1'],2837 )2838 assert returned == [2839 ('utf-8', 1.0), ('utf-7', 1.0), ('unicode-1-1', 1.0)2840 ]2841 @pytest.mark.filterwarnings(IGNORE_BEST_MATCH)2842 def test_best_match(self):2843 accept = AcceptCharsetInvalidHeader(header_value='')2844 assert accept.best_match(['utf-8', 'iso-8859-5']) == 'utf-8'2845 assert accept.best_match([('utf-8', 1), ('iso-8859-5', 0.5)]) == \2846 'utf-8'2847 assert accept.best_match([('utf-8', 0.5), ('iso-8859-5', 1)]) == \2848 'iso-8859-5'2849 assert accept.best_match([('utf-8', 0.5), 'iso-8859-5']) == \2850 'iso-8859-5'2851 assert accept.best_match(2852 [('utf-8', 0.5), 'iso-8859-5'], default_match=True2853 ) == 'iso-8859-5'2854 assert accept.best_match(2855 [('utf-8', 0.5), 'iso-8859-5'], default_match=False2856 ) == 'iso-8859-5'2857 assert accept.best_match([], default_match='fallback') == 'fallback'2858 @pytest.mark.filterwarnings(IGNORE_QUALITY)2859 def test_quality(self):2860 instance = AcceptCharsetInvalidHeader(header_value='')2861 returned = instance.quality(offer='char-set')2862 assert returned == 1.02863class TestCreateAcceptCharsetHeader(object):2864 def test_header_value_is_valid(self):2865 header_value = 'iso-8859-5, unicode-1-1;q=0.8'2866 returned = create_accept_charset_header(header_value=header_value)2867 assert isinstance(returned, AcceptCharsetValidHeader)2868 assert returned.header_value == header_value2869 returned2 = create_accept_charset_header(returned)2870 assert returned2 is not returned2871 assert returned2._header_value == returned._header_value2872 def test_header_value_is_None(self):2873 header_value = None2874 returned = create_accept_charset_header(header_value=header_value)2875 assert isinstance(returned, AcceptCharsetNoHeader)2876 assert returned.header_value == header_value2877 returned2 = create_accept_charset_header(returned)2878 assert returned2 is not returned2879 assert returned2._header_value == returned._header_value2880 @pytest.mark.parametrize('header_value', ['', 'iso-8859-5, unicode/1'])2881 def test_header_value_is_invalid(self, header_value):2882 returned = create_accept_charset_header(header_value=header_value)2883 assert isinstance(returned, AcceptCharsetInvalidHeader)2884 assert returned.header_value == header_value2885 returned2 = create_accept_charset_header(returned)2886 assert returned2 is not returned2887 assert returned2._header_value == returned._header_value2888class TestAcceptCharsetProperty(object):2889 def test_fget_header_is_None(self):2890 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': None})2891 property_ = accept_charset_property()2892 returned = property_.fget(request=request)2893 assert isinstance(returned, AcceptCharsetNoHeader)2894 def test_fget_header_is_valid(self):2895 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': 'UTF-8'})2896 property_ = accept_charset_property()2897 returned = property_.fget(request=request)2898 assert isinstance(returned, AcceptCharsetValidHeader)2899 def test_fget_header_is_invalid(self):2900 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': ''})2901 property_ = accept_charset_property()2902 returned = property_.fget(request=request)2903 assert isinstance(returned, AcceptCharsetInvalidHeader)2904 def test_fset_value_is_None(self):2905 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': 'UTF-8'})2906 property_ = accept_charset_property()2907 property_.fset(request=request, value=None)2908 assert isinstance(request.accept_charset, AcceptCharsetNoHeader)2909 assert 'HTTP_ACCEPT_CHARSET' not in request.environ2910 def test_fset_value_is_invalid(self):2911 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': 'UTF-8'})2912 property_ = accept_charset_property()2913 property_.fset(request=request, value='')2914 assert isinstance(request.accept_charset, AcceptCharsetInvalidHeader)2915 assert request.environ['HTTP_ACCEPT_CHARSET'] == ''2916 def test_fset_value_is_valid(self):2917 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': 'UTF-8'})2918 property_ = accept_charset_property()2919 property_.fset(request=request, value='UTF-7')2920 assert isinstance(request.accept_charset, AcceptCharsetValidHeader)2921 assert request.environ['HTTP_ACCEPT_CHARSET'] == 'UTF-7'2922 @pytest.mark.parametrize('value, value_as_header', [2923 (2924 'utf-8;q=0.5, iso-8859-5;q=0, utf-7',2925 'utf-8;q=0.5, iso-8859-5;q=0, utf-7',2926 ),2927 (2928 [('utf-8', 0.5), ('iso-8859-5', 0.0), 'utf-7'],2929 'utf-8;q=0.5, iso-8859-5;q=0, utf-7',2930 ),2931 (2932 (('utf-8', 0.5), ('iso-8859-5', 0.0), 'utf-7'),2933 'utf-8;q=0.5, iso-8859-5;q=0, utf-7',2934 ),2935 (2936 {'utf-8': 0.5, 'iso-8859-5': 0.0, 'utf-7': 1.0},2937 'utf-7, utf-8;q=0.5, iso-8859-5;q=0',2938 ),2939 ])2940 def test_fset_value_types(self, value, value_as_header):2941 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': ''})2942 property_ = accept_charset_property()2943 property_.fset(request=request, value=value)2944 assert isinstance(request.accept_charset, AcceptCharsetValidHeader)2945 assert request.environ['HTTP_ACCEPT_CHARSET'] == value_as_header2946 def test_fset_other_type_with_valid___str__(self):2947 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': ''})2948 property_ = accept_charset_property()2949 class Other(object):2950 def __str__(self):2951 return 'utf-8;q=0.5, iso-8859-5;q=0, utf-7'2952 value = Other()2953 property_.fset(request=request, value=value)2954 assert isinstance(request.accept_charset, AcceptCharsetValidHeader)2955 assert request.environ['HTTP_ACCEPT_CHARSET'] == str(value)2956 def test_fset_AcceptCharsetNoHeader(self):2957 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': 'utf-8'})2958 property_ = accept_charset_property()2959 header = AcceptCharsetNoHeader()2960 property_.fset(request=request, value=header)2961 assert isinstance(request.accept_charset, AcceptCharsetNoHeader)2962 assert 'HTTP_ACCEPT_CHARSET' not in request.environ2963 def test_fset_AcceptCharsetValidHeader(self):2964 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': 'utf-8'})2965 property_ = accept_charset_property()2966 header = AcceptCharsetValidHeader('utf-7')2967 property_.fset(request=request, value=header)2968 assert isinstance(request.accept_charset, AcceptCharsetValidHeader)2969 assert request.environ['HTTP_ACCEPT_CHARSET'] == header.header_value2970 def test_fset_AcceptCharsetInvalidHeader(self):2971 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': 'utf-8'})2972 property_ = accept_charset_property()2973 header = AcceptCharsetInvalidHeader('')2974 property_.fset(request=request, value=header)2975 assert isinstance(request.accept_charset, AcceptCharsetInvalidHeader)2976 assert request.environ['HTTP_ACCEPT_CHARSET'] == header.header_value2977 def test_fdel_header_key_in_environ(self):2978 request = Request.blank('/', environ={'HTTP_ACCEPT_CHARSET': 'utf-8'})2979 property_ = accept_charset_property()2980 property_.fdel(request=request)2981 assert isinstance(request.accept_charset, AcceptCharsetNoHeader)2982 assert 'HTTP_ACCEPT_CHARSET' not in request.environ2983 def test_fdel_header_key_not_in_environ(self):2984 request = Request.blank('/')2985 property_ = accept_charset_property()2986 property_.fdel(request=request)2987 assert isinstance(request.accept_charset, AcceptCharsetNoHeader)2988 assert 'HTTP_ACCEPT_CHARSET' not in request.environ2989class TestAcceptEncoding(object):2990 @pytest.mark.parametrize('value', [2991 '"',2992 '(',2993 ')',2994 '/',2995 ':',2996 ';',2997 '<',2998 '=',2999 '>',3000 '?',3001 '@',3002 '[',3003 '\\',3004 ']',3005 '{',3006 '}',3007 ', ',3008 ', , ',3009 'gzip;q=1.0, identity; q =0.5, *;q=0',3010 ])3011 def test_parse__invalid_header(self, value):3012 with pytest.raises(ValueError):3013 AcceptEncoding.parse(value=value)3014 @pytest.mark.parametrize('value, expected_list', [3015 (',', []),3016 (', ,', []),3017 ('*', [('*', 1.0)]),3018 ("!#$%&'*+-.^_`|~;q=0.5", [("!#$%&'*+-.^_`|~", 0.5)]),3019 ('0123456789', [('0123456789', 1.0)]),3020 (3021 ',,\t foo \t;\t q=0.345,, bar ; Q=0.456 \t, ,\tCHARLIE \t,, ,',3022 [('foo', 0.345), ('bar', 0.456), ('CHARLIE', 1.0)]3023 ),3024 # RFC 7231, section 5.3.43025 ('compress, gzip', [('compress', 1.0), ('gzip', 1.0)]),3026 ('', []),3027 ('*', [('*', 1.0)]),3028 ('compress;q=0.5, gzip;q=1.0', [('compress', 0.5), ('gzip', 1.0)]),3029 (3030 'gzip;q=1.0, identity; q=0.5, *;q=0',3031 [('gzip', 1.0), ('identity', 0.5), ('*', 0.0)],3032 ),3033 ])3034 def test_parse__valid_header(self, value, expected_list):3035 returned = AcceptEncoding.parse(value=value)3036 list_of_returned = list(returned)3037 assert list_of_returned == expected_list3038class TestAcceptEncodingValidHeader(object):3039 def test_parse__inherited(self):3040 returned = AcceptEncodingValidHeader.parse(3041 value=',,\t gzip;q=1.0, identity; q=0.5, *;q=0 \t ,',3042 )3043 list_of_returned = list(returned)3044 assert list_of_returned == \3045 [('gzip', 1.0), ('identity', 0.5), ('*', 0.0)]3046 @pytest.mark.parametrize('header_value', [3047 ', ',3048 'gzip;q=1.0, identity; q =0.5, *;q=0',3049 ])3050 def test___init___invalid_header(self, header_value):3051 with pytest.raises(ValueError):3052 AcceptEncodingValidHeader(header_value=header_value)3053 def test___init___valid_header(self):3054 header_value = ',,\t gzip;q=1.0, identity; q=0, *;q=0.5 \t ,'3055 instance = AcceptEncodingValidHeader(header_value=header_value)3056 assert instance.header_value == header_value3057 assert instance.parsed == [3058 ('gzip', 1.0), ('identity', 0.0), ('*', 0.5),3059 ]3060 assert instance._parsed_nonzero == [('gzip', 1.0), ('*', 0.5)]3061 assert isinstance(instance, AcceptEncoding)3062 def test___add___None(self):3063 left_operand = AcceptEncodingValidHeader(header_value='gzip')3064 result = left_operand + None3065 assert isinstance(result, AcceptEncodingValidHeader)3066 assert result.header_value == left_operand.header_value3067 assert result is not left_operand3068 @pytest.mark.parametrize('right_operand', [3069 ', ',3070 [', '],3071 (', ',),3072 {', ': 1.0},3073 ])3074 def test___add___invalid_value(self, right_operand):3075 left_operand = AcceptEncodingValidHeader(header_value='gzip')3076 result = left_operand + right_operand3077 assert isinstance(result, AcceptEncodingValidHeader)3078 assert result.header_value == left_operand.header_value3079 assert result is not left_operand3080 def test___add___other_type_with_invalid___str__(self):3081 left_operand = AcceptEncodingValidHeader(header_value='gzip')3082 class Other(object):3083 def __str__(self):3084 return ', '3085 right_operand = Other()3086 result = left_operand + right_operand3087 assert isinstance(result, AcceptEncodingValidHeader)3088 assert result.header_value == left_operand.header_value3089 assert result is not left_operand3090 @pytest.mark.parametrize('value', [3091 '',3092 [],3093 (),3094 {},3095 ])3096 def test___add___valid_empty_value(self, value):3097 left_operand = AcceptEncodingValidHeader(header_value='gzip')3098 result = left_operand + value3099 assert isinstance(result, AcceptEncodingValidHeader)3100 assert result.header_value == left_operand.header_value3101 assert result is not left_operand3102 def test___add___other_type_with_valid___str___empty(self):3103 left_operand = AcceptEncodingValidHeader(header_value='gzip')3104 class Other(object):3105 def __str__(self):3106 return ''3107 result = left_operand + Other()3108 assert isinstance(result, AcceptEncodingValidHeader)3109 assert result.header_value == left_operand.header_value3110 assert result is not left_operand3111 @pytest.mark.parametrize('value, value_as_header', [3112 ('compress;q=0.5, deflate;q=0, *', 'compress;q=0.5, deflate;q=0, *'),3113 (3114 ['compress;q=0.5', 'deflate;q=0', '*'],3115 'compress;q=0.5, deflate;q=0, *',3116 ),3117 (3118 [('compress', 0.5), ('deflate', 0.0), ('*', 1.0)],3119 'compress;q=0.5, deflate;q=0, *',3120 ),3121 (3122 ('compress;q=0.5', 'deflate;q=0', '*'),3123 'compress;q=0.5, deflate;q=0, *',3124 ),3125 (3126 (('compress', 0.5), ('deflate', 0.0), ('*', 1.0)),3127 'compress;q=0.5, deflate;q=0, *',3128 ),3129 (3130 {'compress': 0.5, 'deflate': 0.0, '*': 1.0},3131 '*, compress;q=0.5, deflate;q=0',3132 ),3133 ])3134 def test___add___valid_value(self, value, value_as_header):3135 header = ',\t ,gzip, identity;q=0.333,'3136 result = AcceptEncodingValidHeader(header_value=header) + value3137 assert isinstance(result, AcceptEncodingValidHeader)3138 assert result.header_value == header + ', ' + value_as_header3139 def test___add___other_type_with_valid___str___not_empty(self):3140 header = ',\t ,gzip, identity;q=0.333,'3141 class Other(object):3142 def __str__(self):3143 return 'compress;q=0.5, deflate;q=0, *'3144 right_operand = Other()3145 result = AcceptEncodingValidHeader(header_value=header) + right_operand3146 assert isinstance(result, AcceptEncodingValidHeader)3147 assert result.header_value == header + ', ' + str(right_operand)3148 def test___add___AcceptEncodingValidHeader_header_value_empty(self):3149 left_operand = AcceptEncodingValidHeader(3150 header_value=',\t ,gzip, identity;q=0.333,'3151 )3152 right_operand = AcceptEncodingValidHeader(header_value='')3153 result = left_operand + right_operand3154 assert isinstance(result, AcceptEncodingValidHeader)3155 assert result.header_value == left_operand.header_value3156 assert result is not left_operand3157 def test___add___AcceptEncodingValidHeader_header_value_not_empty(self):3158 left_operand = AcceptEncodingValidHeader(3159 header_value=',\t ,gzip, identity;q=0.333,',3160 )3161 right_operand = AcceptEncodingValidHeader(3162 header_value='compress;q=0.5, deflate;q=0, *',3163 )3164 result = left_operand + right_operand3165 assert isinstance(result, AcceptEncodingValidHeader)3166 assert result.header_value == left_operand.header_value + ', ' + \3167 right_operand.header_value3168 def test___add___AcceptEncodingNoHeader(self):3169 valid_header_instance = AcceptEncodingValidHeader(header_value='gzip')3170 result = valid_header_instance + AcceptEncodingNoHeader()3171 assert isinstance(result, AcceptEncodingValidHeader)3172 assert result.header_value == valid_header_instance.header_value3173 assert result is not valid_header_instance3174 @pytest.mark.parametrize('header_value', [3175 ', ',3176 'compress;q=1.001',3177 ])3178 def test___add___AcceptEncodingInvalidHeader(self, header_value):3179 valid_header_instance = AcceptEncodingValidHeader(header_value='gzip')3180 result = valid_header_instance + AcceptEncodingInvalidHeader(3181 header_value=header_value,3182 )3183 assert isinstance(result, AcceptEncodingValidHeader)3184 assert result.header_value == valid_header_instance.header_value3185 assert result is not valid_header_instance3186 def test___bool__(self):3187 instance = AcceptEncodingValidHeader(header_value='gzip')3188 returned = bool(instance)3189 assert returned is True3190 @pytest.mark.filterwarnings(IGNORE_CONTAINS)3191 def test___contains__(self):3192 accept = AcceptEncodingValidHeader('gzip, compress')3193 assert 'gzip' in accept3194 assert 'deflate' not in accept3195 for mask in ['*', 'gzip', 'gZIP']:3196 assert 'gzip' in AcceptEncodingValidHeader(mask)3197 @pytest.mark.filterwarnings(IGNORE_ITER)3198 def test___iter__(self):3199 instance = AcceptEncodingValidHeader(3200 header_value='gzip; q=0.5, *; q=0, deflate; q=0.8, compress',3201 )3202 assert list(instance) == ['compress', 'deflate', 'gzip']3203 def test___radd___None(self):3204 right_operand = AcceptEncodingValidHeader(header_value='gzip')3205 result = None + right_operand3206 assert isinstance(result, AcceptEncodingValidHeader)3207 assert result.header_value == right_operand.header_value3208 assert result is not right_operand3209 @pytest.mark.parametrize('left_operand', [3210 ', ',3211 [', '],3212 (', ',),3213 {', ': 1.0},3214 ])3215 def test___radd___invalid_value(self, left_operand):3216 right_operand = AcceptEncodingValidHeader(header_value='gzip')3217 result = left_operand + right_operand3218 assert isinstance(result, AcceptEncodingValidHeader)3219 assert result.header_value == right_operand.header_value3220 assert result is not right_operand3221 def test___radd___other_type_with_invalid___str__(self):3222 right_operand = AcceptEncodingValidHeader(header_value='gzip')3223 class Other(object):3224 def __str__(self):3225 return ', '3226 result = Other() + right_operand3227 assert isinstance(result, AcceptEncodingValidHeader)3228 assert result.header_value == right_operand.header_value3229 assert result is not right_operand3230 @pytest.mark.parametrize('value', [3231 '',3232 [],3233 (),3234 {},3235 ])3236 def test___radd___valid_empty_value(self, value):3237 right_operand = AcceptEncodingValidHeader(header_value='gzip')3238 result = value + right_operand3239 assert isinstance(result, AcceptEncodingValidHeader)3240 assert result.header_value == right_operand.header_value3241 assert result is not right_operand3242 def test___radd___other_type_with_valid___str___empty(self):3243 right_operand = AcceptEncodingValidHeader(header_value='gzip')3244 class Other(object):3245 def __str__(self):3246 return ''3247 result = Other() + right_operand3248 assert isinstance(result, AcceptEncodingValidHeader)3249 assert result.header_value == right_operand.header_value3250 assert result is not right_operand3251 @pytest.mark.parametrize('value, value_as_header', [3252 ('compress;q=0.5, deflate;q=0, *', 'compress;q=0.5, deflate;q=0, *'),3253 (3254 ['compress;q=0.5', 'deflate;q=0', '*'],3255 'compress;q=0.5, deflate;q=0, *',3256 ),3257 (3258 [('compress', 0.5), ('deflate', 0.0), ('*', 1.0)],3259 'compress;q=0.5, deflate;q=0, *',3260 ),3261 (3262 ('compress;q=0.5', 'deflate;q=0', '*'),3263 'compress;q=0.5, deflate;q=0, *',3264 ),3265 (3266 (('compress', 0.5), ('deflate', 0.0), ('*', 1.0)),3267 'compress;q=0.5, deflate;q=0, *',3268 ),3269 (3270 {'compress': 0.5, 'deflate': 0.0, '*': 1.0},3271 '*, compress;q=0.5, deflate;q=0',3272 ),3273 ])3274 def test___radd___valid_non_empty_value(self, value, value_as_header):3275 header = ',\t ,gzip, identity;q=0.333,'3276 result = value + AcceptEncodingValidHeader(header_value=header)3277 assert isinstance(result, AcceptEncodingValidHeader)3278 assert result.header_value == value_as_header + ', ' + header3279 def test___radd___other_type_with_valid___str___not_empty(self):3280 header = ',\t ,gzip, identity;q=0.333,'3281 class Other(object):3282 def __str__(self):3283 return 'compress;q=0.5, deflate;q=0, *'3284 left_operand = Other()3285 result = left_operand + AcceptEncodingValidHeader(header_value=header)3286 assert isinstance(result, AcceptEncodingValidHeader)3287 assert result.header_value == str(left_operand) + ', ' + header3288 @pytest.mark.parametrize('header_value, expected_returned', [3289 ('', "<AcceptEncodingValidHeader ('')>"),3290 (3291 ",\t, a ;\t q=0.20 , b ,',",3292 # single quote is valid character in token3293 """<AcceptEncodingValidHeader ("a;q=0.2, b, \'")>"""3294 ),3295 ])3296 def test___repr__(self, header_value, expected_returned):3297 instance = AcceptEncodingValidHeader(header_value=header_value)3298 assert repr(instance) == expected_returned3299 @pytest.mark.parametrize('header_value, expected_returned', [3300 ('', ''),3301 (",\t, a ;\t q=0.20 , b ,',", "a;q=0.2, b, '"),3302 ])3303 def test___str__(self, header_value, expected_returned):3304 instance = AcceptEncodingValidHeader(header_value=header_value)3305 assert str(instance) == expected_returned3306 @pytest.mark.parametrize('header_value, offers, expected_returned', [3307 ('', [], []),3308 ('gzip, compress', [], []),3309 ('', ['gzip', 'deflate'], []),3310 ('', ['gzip', 'identity'], [('identity', 1.0)]),3311 ('compress, deflate, gzip', ['identity'], [('identity', 1.0)]),3312 ('compress, identity;q=0, gzip', ['identity'], []),3313 # *;q=0 does not make sense, but is valid3314 ('*;q=0', ['identity'], []),3315 ('*;q=0, deflate, gzip', ['identity'], []),3316 ('*;q=0, deflate, identity;q=0, gzip', ['identity'], []),3317 (3318 '*;q=0, deflate, identity;q=0.1, gzip',3319 ['identity'],3320 [('identity', 0.1)],3321 ),3322 (3323 'compress, deflate, gzip',3324 ['identity', 'gzip'],3325 [('identity', 1.0), ('gzip', 1.0)],3326 ),3327 (3328 'compress, deflate, gzip',3329 ['gzip', 'identity'],3330 [('gzip', 1.0), ('identity', 1.0)],3331 ),3332 (3333 'IDentity;q=0.5, deflATE;q=0, gZIP;q=0, COMPress',3334 ['GZip', 'DEFlate', 'IDENTity', 'comPRESS'],3335 [('comPRESS', 1.0), ('IDENTity', 0.5)],3336 ),3337 (3338 'compress;q=0, identity, *;q=0.5, identity;q=0, *;q=0, compress',3339 # does not make sense, but is valid3340 ['compress', 'identity', 'deflate', 'gzip'],3341 [('identity', 1.0), ('deflate', 0.5), ('gzip', 0.5)],3342 ),3343 ])3344 def test_acceptable_offers(3345 self, header_value, offers, expected_returned,3346 ):3347 instance = AcceptEncodingValidHeader(header_value=header_value)3348 returned = instance.acceptable_offers(offers=offers)3349 assert returned == expected_returned3350 @pytest.mark.filterwarnings(IGNORE_BEST_MATCH)3351 def test_best_match(self):3352 accept = AcceptEncodingValidHeader('gzip, iso-8859-5')3353 assert accept.best_match(['gzip', 'iso-8859-5']) == 'gzip'3354 assert accept.best_match(['iso-8859-5', 'gzip']) == 'iso-8859-5'3355 assert accept.best_match([('iso-8859-5', 0.5), 'gzip']) == 'gzip'3356 assert accept.best_match([('iso-8859-5', 0.5), ('gzip', 0.4)]) == \3357 'iso-8859-5'3358 @pytest.mark.filterwarnings(IGNORE_BEST_MATCH)3359 def test_best_match_with_one_lower_q(self):3360 accept = AcceptEncodingValidHeader('gzip, compress;q=0.5')3361 assert accept.best_match(['gzip', 'compress']) == 'gzip'3362 accept = AcceptEncodingValidHeader('gzip;q=0.5, compress')3363 assert accept.best_match(['gzip', 'compress']) == 'compress'3364 @pytest.mark.filterwarnings(IGNORE_BEST_MATCH)3365 def test_best_match_with_complex_q(self):3366 accept = AcceptEncodingValidHeader(3367 'gzip, compress;q=0.55, deflate;q=0.59'3368 )3369 assert accept.best_match(['gzip', 'compress']) == 'gzip'3370 accept = AcceptEncodingValidHeader(3371 'gzip;q=0.5, compress;q=0.586, deflate;q=0.596'3372 )3373 assert accept.best_match(['gzip', 'deflate']) == 'deflate'3374 @pytest.mark.filterwarnings(IGNORE_BEST_MATCH)3375 def test_best_match_mixedcase(self):3376 accept = AcceptEncodingValidHeader(3377 'gZiP; q=0.2, COMPress; Q=0.4, *; q=0.05'3378 )3379 assert accept.best_match(['gzIP']) == 'gzIP'3380 assert accept.best_match(['DeFlAte']) == 'DeFlAte'3381 assert accept.best_match(['deflaTe', 'compRess', 'UtF-8']) == \3382 'compRess'3383 @pytest.mark.filterwarnings(IGNORE_BEST_MATCH)3384 @pytest.mark.filterwarnings(IGNORE_CONTAINS)3385 def test_best_match_zero_quality(self):3386 assert AcceptEncodingValidHeader('deflate, *;q=0').best_match(3387 ['gzip']3388 ) is None3389 assert 'content-coding' not in AcceptEncodingValidHeader('*;q=0')3390 @pytest.mark.filterwarnings(IGNORE_QUALITY)3391 def test_quality(self):3392 accept = AcceptEncodingValidHeader('gzip')3393 assert accept.quality('gzip') == 13394 accept = AcceptEncodingValidHeader('gzip;q=0.5')3395 assert accept.quality('gzip') == 0.53396 @pytest.mark.filterwarnings(IGNORE_QUALITY)3397 def test_quality_not_found(self):3398 accept = AcceptEncodingValidHeader('gzip')3399 assert accept.quality('compress') is None3400class TestAcceptEncodingNoHeader(object):3401 def test_parse__inherited(self):3402 returned = AcceptEncodingNoHeader.parse(3403 value=',,\t gzip;q=1.0, identity; q=0.5, *;q=0 \t ,',3404 )3405 list_of_returned = list(returned)3406 assert list_of_returned == \3407 [('gzip', 1.0), ('identity', 0.5), ('*', 0.0)]3408 def test___init__(self):3409 instance = AcceptEncodingNoHeader()3410 assert instance.header_value is None3411 assert instance.parsed is None3412 assert instance._parsed_nonzero is None3413 assert isinstance(instance, AcceptEncoding)3414 def test___add___None(self):3415 left_operand = AcceptEncodingNoHeader()3416 result = left_operand + None3417 assert isinstance(result, AcceptEncodingNoHeader)3418 @pytest.mark.parametrize('right_operand', [3419 ', ',3420 [', '],3421 (', ',),3422 {', ': 1.0},3423 ])3424 def test___add___invalid_value(self, right_operand):3425 left_operand = AcceptEncodingNoHeader()3426 result = left_operand + right_operand3427 assert isinstance(result, AcceptEncodingNoHeader)3428 def test___add___other_type_with_invalid___str__(self):3429 left_operand = AcceptEncodingNoHeader()3430 class Other(object):3431 def __str__(self):3432 return ', '3433 right_operand = Other()3434 result = left_operand + right_operand3435 assert isinstance(result, AcceptEncodingNoHeader)3436 @pytest.mark.parametrize('value', [3437 '',3438 [],3439 (),3440 {},3441 ])3442 def test___add___valid_empty_value(self, value):3443 left_operand = AcceptEncodingNoHeader()3444 result = left_operand + value3445 assert isinstance(result, AcceptEncodingValidHeader)3446 assert result.header_value == ''3447 def test___add___other_type_with_valid___str___empty(self):3448 left_operand = AcceptEncodingNoHeader()3449 class Other(object):3450 def __str__(self):3451 return ''3452 result = left_operand + Other()3453 assert isinstance(result, AcceptEncodingValidHeader)3454 assert result.header_value == ''3455 @pytest.mark.parametrize('value, value_as_header', [3456 ('compress;q=0.5, deflate;q=0, *', 'compress;q=0.5, deflate;q=0, *'),3457 (3458 ['compress;q=0.5', 'deflate;q=0', '*'],3459 'compress;q=0.5, deflate;q=0, *',3460 ),3461 (3462 [('compress', 0.5), ('deflate', 0.0), ('*', 1.0)],3463 'compress;q=0.5, deflate;q=0, *',3464 ),3465 (3466 ('compress;q=0.5', 'deflate;q=0', '*'),3467 'compress;q=0.5, deflate;q=0, *',3468 ),3469 (3470 (('compress', 0.5), ('deflate', 0.0), ('*', 1.0)),3471 'compress;q=0.5, deflate;q=0, *',3472 ),3473 (3474 {'compress': 0.5, 'deflate': 0.0, '*': 1.0},3475 '*, compress;q=0.5, deflate;q=0',3476 ),3477 ])3478 def test___add___valid_value(self, value, value_as_header):3479 result = AcceptEncodingNoHeader() + value3480 assert isinstance(result, AcceptEncodingValidHeader)3481 assert result.header_value == value_as_header3482 def test___add___other_type_with_valid___str___not_empty(self):3483 class Other(object):3484 def __str__(self):3485 return 'compress;q=0.5, deflate;q=0, *'3486 right_operand = Other()3487 result = AcceptEncodingNoHeader() + right_operand3488 assert isinstance(result, AcceptEncodingValidHeader)3489 assert result.header_value == str(right_operand)3490 def test___add___AcceptEncodingValidHeader_header_value_empty(self):3491 right_operand = AcceptEncodingValidHeader(header_value='')3492 result = AcceptEncodingNoHeader() + right_operand3493 assert isinstance(result, AcceptEncodingValidHeader)3494 assert result.header_value == right_operand.header_value3495 assert result is not right_operand3496 def test___add___AcceptEncodingValidHeader_header_value_not_empty(self):3497 right_operand = AcceptEncodingValidHeader(3498 header_value='compress;q=0.5, deflate;q=0, *',3499 )3500 result = AcceptEncodingNoHeader() + right_operand3501 assert isinstance(result, AcceptEncodingValidHeader)3502 assert result.header_value == right_operand.header_value3503 def test___add___AcceptEncodingNoHeader(self):3504 left_operand = AcceptEncodingNoHeader()3505 right_operand = AcceptEncodingNoHeader()3506 result = left_operand + right_operand3507 assert isinstance(result, AcceptEncodingNoHeader)3508 assert result is not left_operand3509 assert result is not right_operand3510 @pytest.mark.parametrize('header_value', [3511 ', ',3512 'compress;q=1.001',3513 ])3514 def test___add___AcceptEncodingInvalidHeader(self, header_value):3515 left_operand = AcceptEncodingNoHeader()3516 result = left_operand + AcceptEncodingInvalidHeader(3517 header_value=header_value,3518 )3519 assert isinstance(result, AcceptEncodingNoHeader)3520 assert result is not left_operand3521 def test___bool__(self):3522 instance = AcceptEncodingNoHeader()3523 returned = bool(instance)3524 assert returned is False3525 @pytest.mark.filterwarnings(IGNORE_CONTAINS)3526 def test___contains__(self):3527 instance = AcceptEncodingNoHeader()3528 returned = ('content-coding' in instance)3529 assert returned is True3530 @pytest.mark.filterwarnings(IGNORE_ITER)3531 def test___iter__(self):3532 instance = AcceptEncodingNoHeader()3533 returned = list(instance)3534 assert returned == []3535 def test___radd___None(self):3536 right_operand = AcceptEncodingNoHeader()3537 result = None + right_operand3538 assert isinstance(result, AcceptEncodingNoHeader)3539 assert result is not right_operand3540 @pytest.mark.parametrize('left_operand', [3541 ', ',3542 [', '],3543 (', ',),3544 {', ': 1.0},3545 ])3546 def test___radd___invalid_value(self, left_operand):3547 right_operand = AcceptEncodingNoHeader()3548 result = left_operand + right_operand3549 assert isinstance(result, AcceptEncodingNoHeader)3550 assert result is not right_operand3551 def test___radd___other_type_with_invalid___str__(self):3552 right_operand = AcceptEncodingNoHeader()3553 class Other(object):3554 def __str__(self):3555 return ', '3556 result = Other() + right_operand3557 assert isinstance(result, AcceptEncodingNoHeader)3558 assert result is not right_operand3559 @pytest.mark.parametrize('value', [3560 '',3561 [],3562 (),3563 {},3564 ])3565 def test___radd___valid_empty_value(self, value):3566 result = value + AcceptEncodingNoHeader()3567 assert isinstance(result, AcceptEncodingValidHeader)3568 assert result.header_value == ''3569 def test___radd___other_type_with_valid___str___empty(self):3570 class Other(object):3571 def __str__(self):3572 return ''3573 result = Other() + AcceptEncodingNoHeader()3574 assert isinstance(result, AcceptEncodingValidHeader)3575 assert result.header_value == ''3576 @pytest.mark.parametrize('value, value_as_header', [3577 ('compress;q=0.5, deflate;q=0, *', 'compress;q=0.5, deflate;q=0, *'),3578 (3579 ['compress;q=0.5', 'deflate;q=0', '*'],3580 'compress;q=0.5, deflate;q=0, *',3581 ),3582 (3583 [('compress', 0.5), ('deflate', 0.0), ('*', 1.0)],3584 'compress;q=0.5, deflate;q=0, *',3585 ),3586 (3587 ('compress;q=0.5', 'deflate;q=0', '*'),3588 'compress;q=0.5, deflate;q=0, *',3589 ),3590 (3591 (('compress', 0.5), ('deflate', 0.0), ('*', 1.0)),3592 'compress;q=0.5, deflate;q=0, *',3593 ),3594 (3595 {'compress': 0.5, 'deflate': 0.0, '*': 1.0},3596 '*, compress;q=0.5, deflate;q=0',3597 ),3598 ])3599 def test___radd___valid_non_empty_value(self, value, value_as_header):3600 result = value + AcceptEncodingNoHeader()3601 assert isinstance(result, AcceptEncodingValidHeader)3602 assert result.header_value == value_as_header3603 def test___radd___other_type_with_valid___str___not_empty(self):3604 class Other(object):3605 def __str__(self):3606 return 'compress;q=0.5, deflate;q=0, *'3607 left_operand = Other()3608 result = left_operand + AcceptEncodingNoHeader()3609 assert isinstance(result, AcceptEncodingValidHeader)3610 assert result.header_value == str(left_operand)3611 def test___repr__(self):3612 instance = AcceptEncodingNoHeader()3613 assert repr(instance) == '<AcceptEncodingNoHeader>'3614 def test___str__(self):3615 instance = AcceptEncodingNoHeader()3616 assert str(instance) == '<no header in request>'3617 def test_acceptable_offers(self):3618 instance = AcceptEncodingNoHeader()3619 returned = instance.acceptable_offers(offers=['a', 'b', 'c'])3620 assert returned == [('a', 1.0), ('b', 1.0), ('c', 1.0)]3621 @pytest.mark.filterwarnings(IGNORE_BEST_MATCH)3622 def test_best_match(self):3623 accept = AcceptEncodingNoHeader()3624 assert accept.best_match(['gzip', 'compress']) == 'gzip'3625 assert accept.best_match([('gzip', 1), ('compress', 0.5)]) == 'gzip'3626 assert accept.best_match([('gzip', 0.5), ('compress', 1)]) == \3627 'compress'3628 assert accept.best_match([('gzip', 0.5), 'compress']) == 'compress'3629 assert accept.best_match(3630 [('gzip', 0.5), 'compress'], default_match=True3631 ) == 'compress'3632 assert accept.best_match(3633 [('gzip', 0.5), 'compress'], default_match=False3634 ) == 'compress'3635 assert accept.best_match([], default_match='fallback') == 'fallback'3636 @pytest.mark.filterwarnings(IGNORE_QUALITY)3637 def test_quality(self):3638 instance = AcceptEncodingNoHeader()3639 returned = instance.quality(offer='content-coding')3640 assert returned == 1.03641class TestAcceptEncodingInvalidHeader(object):3642 def test_parse__inherited(self):3643 returned = AcceptEncodingInvalidHeader.parse(3644 value=',,\t gzip;q=1.0, identity; q=0.5, *;q=0 \t ,',3645 )3646 list_of_returned = list(returned)3647 assert list_of_returned == \3648 [('gzip', 1.0), ('identity', 0.5), ('*', 0.0)]3649 def test___init__(self):3650 header_value = 'invalid header'3651 instance = AcceptEncodingInvalidHeader(header_value=header_value)3652 assert instance.header_value == header_value3653 assert instance.parsed is None3654 assert instance._parsed_nonzero is None3655 assert isinstance(instance, AcceptEncoding)3656 def test___add___None(self):3657 left_operand = AcceptEncodingInvalidHeader(header_value=', ')3658 result = left_operand + None3659 assert isinstance(result, AcceptEncodingNoHeader)3660 @pytest.mark.parametrize('right_operand', [3661 ', ',3662 [', '],3663 (', ',),3664 {', ': 1.0},3665 ])3666 def test___add___invalid_value(self, right_operand):3667 left_operand = AcceptEncodingInvalidHeader(3668 header_value='invalid header',3669 )3670 result = left_operand + right_operand3671 assert isinstance(result, AcceptEncodingNoHeader)3672 def test___add___other_type_with_invalid___str__(self):3673 left_operand = AcceptEncodingInvalidHeader(3674 header_value='invalid header',3675 )3676 class Other(object):3677 def __str__(self):3678 return ', '3679 right_operand = Other()3680 result = left_operand + right_operand3681 assert isinstance(result, AcceptEncodingNoHeader)3682 @pytest.mark.parametrize('value', [3683 '',3684 [],3685 (),3686 {},3687 ])3688 def test___add___valid_empty_value(self, value):3689 left_operand = AcceptEncodingInvalidHeader(header_value=', ')3690 result = left_operand + value3691 assert isinstance(result, AcceptEncodingValidHeader)3692 assert result.header_value == ''3693 def test___add___other_type_with_valid___str___empty(self):3694 left_operand = AcceptEncodingInvalidHeader(header_value=', ')3695 class Other(object):3696 def __str__(self):3697 return ''3698 result = left_operand + Other()3699 assert isinstance(result, AcceptEncodingValidHeader)3700 assert result.header_value == ''3701 @pytest.mark.parametrize('value, value_as_header', [3702 ('compress;q=0.5, deflate;q=0, *', 'compress;q=0.5, deflate;q=0, *'),3703 (3704 ['compress;q=0.5', 'deflate;q=0', '*'],3705 'compress;q=0.5, deflate;q=0, *',3706 ),3707 (3708 [('compress', 0.5), ('deflate', 0.0), ('*', 1.0)],3709 'compress;q=0.5, deflate;q=0, *',3710 ),3711 (3712 ('compress;q=0.5', 'deflate;q=0', '*'),3713 'compress;q=0.5, deflate;q=0, *',3714 ),3715 (3716 (('compress', 0.5), ('deflate', 0.0), ('*', 1.0)),3717 'compress;q=0.5, deflate;q=0, *',3718 ),3719 (3720 {'compress': 0.5, 'deflate': 0.0, '*': 1.0},3721 '*, compress;q=0.5, deflate;q=0',3722 ),3723 ])3724 def test___add___valid_value(self, value, value_as_header):3725 result = AcceptEncodingInvalidHeader(header_value=', ') + value3726 assert isinstance(result, AcceptEncodingValidHeader)3727 assert result.header_value == value_as_header3728 def test___add___other_type_with_valid___str___not_empty(self):3729 class Other(object):3730 def __str__(self):3731 return '*, compress;q=0.5, deflate;q=0'3732 right_operand = Other()3733 result = AcceptEncodingInvalidHeader(header_value=', ') + right_operand3734 assert isinstance(result, AcceptEncodingValidHeader)3735 assert result.header_value == str(right_operand)3736 def test___add___AcceptEncodingValidHeader_header_value_empty(self):3737 left_operand = AcceptEncodingInvalidHeader(header_value=', ')3738 right_operand = AcceptEncodingValidHeader(header_value='')3739 result = left_operand + right_operand3740 assert isinstance(result, AcceptEncodingValidHeader)3741 assert result.header_value == right_operand.header_value3742 assert result is not right_operand3743 def test___add___AcceptEncodingValidHeader_header_value_not_empty(self):3744 left_operand = AcceptEncodingInvalidHeader(header_value=', ')3745 right_operand = AcceptEncodingValidHeader(3746 header_value='compress;q=0.5, deflate;q=0, *',3747 )3748 result = left_operand + right_operand3749 assert isinstance(result, AcceptEncodingValidHeader)3750 assert result.header_value == right_operand.header_value3751 def test___add___AcceptEncodingNoHeader(self):3752 left_operand = AcceptEncodingInvalidHeader(header_value=', ')3753 right_operand = AcceptEncodingNoHeader()3754 result = left_operand + right_operand3755 assert isinstance(result, AcceptEncodingNoHeader)3756 assert result is not right_operand3757 @pytest.mark.parametrize('header_value', [3758 ', ',3759 'compress;q=1.001',3760 ])3761 def test___add___AcceptEncodingInvalidHeader(self, header_value):3762 result = AcceptEncodingInvalidHeader(header_value='gzip;;q=1') + \3763 AcceptEncodingInvalidHeader(header_value=header_value)3764 assert isinstance(result, AcceptEncodingNoHeader)3765 def test___bool__(self):3766 instance = AcceptEncodingInvalidHeader(header_value=', ')3767 returned = bool(instance)3768 assert returned is False3769 @pytest.mark.filterwarnings(IGNORE_CONTAINS)3770 def test___contains__(self):3771 instance = AcceptEncodingInvalidHeader(header_value=', ')3772 returned = ('content-coding' in instance)3773 assert returned is True3774 @pytest.mark.filterwarnings(IGNORE_ITER)3775 def test___iter__(self):3776 instance = AcceptEncodingInvalidHeader(header_value=', ')3777 returned = list(instance)3778 assert returned == []3779 def test___radd___None(self):3780 right_operand = AcceptEncodingInvalidHeader(header_value=', ')3781 result = None + right_operand3782 assert isinstance(result, AcceptEncodingNoHeader)3783 @pytest.mark.parametrize('left_operand', [3784 ', ',3785 [', '],3786 (', ',),3787 {', ': 1.0},3788 ])3789 def test___radd___invalid_value(self, left_operand):3790 right_operand = AcceptEncodingInvalidHeader(header_value='gzip;q= 1')3791 result = left_operand + right_operand3792 assert isinstance(result, AcceptEncodingNoHeader)3793 def test___radd___other_type_with_invalid___str__(self):3794 right_operand = AcceptEncodingInvalidHeader(header_value='gzip;q= 1')3795 class Other(object):3796 def __str__(self):3797 return ', '3798 result = Other() + right_operand3799 assert isinstance(result, AcceptEncodingNoHeader)3800 @pytest.mark.parametrize('value', [3801 '',3802 [],3803 (),3804 {},3805 ])3806 def test___radd___valid_empty_value(self, value):3807 right_operand = AcceptEncodingInvalidHeader(header_value=', ')3808 result = value + right_operand3809 assert isinstance(result, AcceptEncodingValidHeader)3810 assert result.header_value == ''3811 def test___radd___other_type_with_valid___str___empty(self):3812 right_operand = AcceptEncodingInvalidHeader(header_value=', ')3813 class Other(object):3814 def __str__(self):3815 return ''3816 result = Other() + right_operand3817 assert isinstance(result, AcceptEncodingValidHeader)3818 assert result.header_value == ''3819 @pytest.mark.parametrize('value, value_as_header', [3820 ('compress;q=0.5, deflate;q=0, *', 'compress;q=0.5, deflate;q=0, *'),3821 (3822 ['compress;q=0.5', 'deflate;q=0', '*'],3823 'compress;q=0.5, deflate;q=0, *',3824 ),3825 (3826 [('compress', 0.5), ('deflate', 0.0), ('*', 1.0)],3827 'compress;q=0.5, deflate;q=0, *',3828 ),3829 (3830 ('compress;q=0.5', 'deflate;q=0', '*'),3831 'compress;q=0.5, deflate;q=0, *',3832 ),3833 (3834 (('compress', 0.5), ('deflate', 0.0), ('*', 1.0)),3835 'compress;q=0.5, deflate;q=0, *',3836 ),3837 (3838 {'compress': 0.5, 'deflate': 0.0, '*': 1.0},3839 '*, compress;q=0.5, deflate;q=0',3840 ),3841 ])3842 def test___radd___valid_non_empty_value(self, value, value_as_header):3843 result = value + AcceptEncodingInvalidHeader(header_value=', ')3844 assert isinstance(result, AcceptEncodingValidHeader)3845 assert result.header_value == value_as_header3846 def test___radd___other_type_with_valid___str___not_empty(self):3847 class Other(object):3848 def __str__(self):3849 return 'compress;q=0.5, deflate;q=0, *'3850 left_operand = Other()3851 result = left_operand + AcceptEncodingInvalidHeader(header_value=', ')3852 assert isinstance(result, AcceptEncodingValidHeader)3853 assert result.header_value == str(left_operand)3854 def test___repr__(self):3855 instance = AcceptEncodingInvalidHeader(header_value='\x00')3856 assert repr(instance) == '<AcceptEncodingInvalidHeader>'3857 def test___str__(self):3858 instance = AcceptEncodingInvalidHeader(header_value=", ")3859 assert str(instance) == '<invalid header value>'3860 def test_acceptable_offers(self):3861 instance = AcceptEncodingInvalidHeader(header_value=', ')3862 returned = instance.acceptable_offers(offers=['a', 'b', 'c'])3863 assert returned == [('a', 1.0), ('b', 1.0), ('c', 1.0)]3864 @pytest.mark.filterwarnings(IGNORE_BEST_MATCH)3865 def test_best_match(self):3866 accept = AcceptEncodingInvalidHeader(header_value=', ')3867 assert accept.best_match(['gzip', 'compress']) == 'gzip'3868 assert accept.best_match([('gzip', 1), ('compress', 0.5)]) == 'gzip'3869 assert accept.best_match([('gzip', 0.5), ('compress', 1)]) == \3870 'compress'3871 assert accept.best_match([('gzip', 0.5), 'compress']) == 'compress'3872 assert accept.best_match(3873 [('gzip', 0.5), 'compress'], default_match=True3874 ) == 'compress'3875 assert accept.best_match(3876 [('gzip', 0.5), 'compress'], default_match=False3877 ) == 'compress'3878 assert accept.best_match([], default_match='fallback') == 'fallback'3879 @pytest.mark.filterwarnings(IGNORE_QUALITY)3880 def test_quality(self):3881 instance = AcceptEncodingInvalidHeader(header_value=', ')3882 returned = instance.quality(offer='content-coding')3883 assert returned == 1.03884class TestCreateAcceptEncodingHeader(object):3885 def test_header_value_is_None(self):3886 header_value = None3887 returned = create_accept_encoding_header(header_value=header_value)3888 assert isinstance(returned, AcceptEncodingNoHeader)3889 assert returned.header_value == header_value3890 returned2 = create_accept_encoding_header(returned)3891 assert returned2 is not returned3892 assert returned2._header_value == returned._header_value3893 def test_header_value_is_valid(self):3894 header_value = 'gzip, identity;q=0.9'3895 returned = create_accept_encoding_header(header_value=header_value)3896 assert isinstance(returned, AcceptEncodingValidHeader)3897 assert returned.header_value == header_value3898 returned2 = create_accept_encoding_header(returned)3899 assert returned2 is not returned3900 assert returned2._header_value == returned._header_value3901 @pytest.mark.parametrize('header_value', [', ', 'gzip;q= 1'])3902 def test_header_value_is_invalid(self, header_value):3903 returned = create_accept_encoding_header(header_value=header_value)3904 assert isinstance(returned, AcceptEncodingInvalidHeader)3905 assert returned.header_value == header_value3906 returned2 = create_accept_encoding_header(returned)3907 assert returned2 is not returned3908 assert returned2._header_value == returned._header_value3909class TestAcceptEncodingProperty(object):3910 def test_fget_header_is_None(self):3911 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': None})3912 property_ = accept_encoding_property()3913 returned = property_.fget(request=request)3914 assert isinstance(returned, AcceptEncodingNoHeader)3915 def test_fget_header_is_valid(self):3916 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': 'gzip'})3917 property_ = accept_encoding_property()3918 returned = property_.fget(request=request)3919 assert isinstance(returned, AcceptEncodingValidHeader)3920 def test_fget_header_is_invalid(self):3921 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': ', '})3922 property_ = accept_encoding_property()3923 returned = property_.fget(request=request)3924 assert isinstance(returned, AcceptEncodingInvalidHeader)3925 def test_fset_value_is_None(self):3926 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': 'gzip'})3927 property_ = accept_encoding_property()3928 property_.fset(request=request, value=None)3929 assert isinstance(request.accept_encoding, AcceptEncodingNoHeader)3930 assert 'HTTP_ACCEPT_ENCODING' not in request.environ3931 def test_fset_value_is_invalid(self):3932 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': 'gzip'})3933 property_ = accept_encoding_property()3934 property_.fset(request=request, value=', ')3935 assert isinstance(request.accept_encoding, AcceptEncodingInvalidHeader)3936 assert request.environ['HTTP_ACCEPT_ENCODING'] == ', '3937 def test_fset_value_is_valid(self):3938 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': 'gzip'})3939 property_ = accept_encoding_property()3940 property_.fset(request=request, value='compress')3941 assert isinstance(request.accept_encoding, AcceptEncodingValidHeader)3942 assert request.environ['HTTP_ACCEPT_ENCODING'] == 'compress'3943 @pytest.mark.parametrize('value, value_as_header', [3944 (3945 'gzip;q=0.5, compress;q=0, deflate',3946 'gzip;q=0.5, compress;q=0, deflate',3947 ),3948 (3949 [('gzip', 0.5), ('compress', 0.0), 'deflate'],3950 'gzip;q=0.5, compress;q=0, deflate',3951 ),3952 (3953 (('gzip', 0.5), ('compress', 0.0), 'deflate'),3954 'gzip;q=0.5, compress;q=0, deflate',3955 ),3956 (3957 {'gzip': 0.5, 'compress': 0.0, 'deflate': 1.0},3958 'deflate, gzip;q=0.5, compress;q=0',3959 ),3960 ])3961 def test_fset_value_types(self, value, value_as_header):3962 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': ''})3963 property_ = accept_encoding_property()3964 property_.fset(request=request, value=value)3965 assert isinstance(request.accept_encoding, AcceptEncodingValidHeader)3966 assert request.environ['HTTP_ACCEPT_ENCODING'] == value_as_header3967 def test_fset_other_type_with_valid___str__(self):3968 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': ''})3969 property_ = accept_encoding_property()3970 class Other(object):3971 def __str__(self):3972 return 'gzip;q=0.5, compress;q=0, deflate'3973 value = Other()3974 property_.fset(request=request, value=value)3975 assert isinstance(request.accept_encoding, AcceptEncodingValidHeader)3976 assert request.environ['HTTP_ACCEPT_ENCODING'] == str(value)3977 def test_fset_AcceptEncodingNoHeader(self):3978 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': ''})3979 property_ = accept_encoding_property()3980 header = AcceptEncodingNoHeader()3981 property_.fset(request=request, value=header)3982 assert isinstance(request.accept_encoding, AcceptEncodingNoHeader)3983 assert 'HTTP_ACCEPT_ENCODING' not in request.environ3984 def test_fset_AcceptEncodingValidHeader(self):3985 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': ''})3986 property_ = accept_encoding_property()3987 header = AcceptEncodingValidHeader('gzip')3988 property_.fset(request=request, value=header)3989 assert isinstance(request.accept_encoding, AcceptEncodingValidHeader)3990 assert request.environ['HTTP_ACCEPT_ENCODING'] == header.header_value3991 def test_fset_AcceptEncodingInvalidHeader(self):3992 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': 'gzip'})3993 property_ = accept_encoding_property()3994 header = AcceptEncodingInvalidHeader(', ')3995 property_.fset(request=request, value=header)3996 assert isinstance(request.accept_encoding, AcceptEncodingInvalidHeader)3997 assert request.environ['HTTP_ACCEPT_ENCODING'] == header.header_value3998 def test_fdel_header_key_in_environ(self):3999 request = Request.blank('/', environ={'HTTP_ACCEPT_ENCODING': 'gzip'})4000 property_ = accept_encoding_property()4001 property_.fdel(request=request)4002 assert isinstance(request.accept_encoding, AcceptEncodingNoHeader)4003 assert 'HTTP_ACCEPT_ENCODING' not in request.environ4004 def test_fdel_header_key_not_in_environ(self):4005 request = Request.blank('/')4006 property_ = accept_encoding_property()4007 property_.fdel(request=request)4008 assert isinstance(request.accept_encoding, AcceptEncodingNoHeader)4009 assert 'HTTP_ACCEPT_ENCODING' not in request.environ4010class TestAcceptLanguage(object):4011 @pytest.mark.parametrize('value', [4012 '',4013 '*s',4014 '*-a',4015 'a-*',4016 'a' * 9,4017 'a-' + 'a' * 9,4018 'a-a-' + 'a' * 9,4019 '-',4020 'a-',4021 '-a',4022 '---',4023 '--a',4024 '1-a',4025 '1-a-a',4026 'en_gb',4027 'en/gb',4028 'foo, bar, baz;q= 0.001',4029 'foo , ,bar,charlie ',4030 ])4031 def test_parse__invalid_header(self, value):4032 with pytest.raises(ValueError):4033 AcceptLanguage.parse(value=value)4034 @pytest.mark.parametrize('value, expected_list', [4035 ('*', [('*', 1.0)]),4036 ('fR;q=0.5', [('fR', 0.5)]),4037 ('zh-Hant;q=0.500', [('zh-Hant', 0.5)]),4038 ('zh-Hans-CN;q=1', [('zh-Hans-CN', 1.0)]),4039 ('de-CH-x-phonebk;q=1.0', [('de-CH-x-phonebk', 1.0)]),4040 ('az-Arab-x-AZE-derbend;q=1.00', [('az-Arab-x-AZE-derbend', 1.0)]),4041 ('zh-CN-a-myExt-x-private;q=1.000', [('zh-CN-a-myExt-x-private', 1.0)]),4042 ('aaaaaaaa', [('aaaaaaaa', 1.0)]),4043 ('aaaaaaaa-a', [('aaaaaaaa-a', 1.0)]),4044 ('aaaaaaaa-aaaaaaaa', [('aaaaaaaa-aaaaaaaa', 1.0)]),4045 ('a-aaaaaaaa-aaaaaaaa', [('a-aaaaaaaa-aaaaaaaa', 1.0)]),4046 ('aaaaaaaa-a-aaaaaaaa', [('aaaaaaaa-a-aaaaaaaa', 1.0)]),4047 (4048 'zh-Hant;q=0.372,zh-CN-a-myExt-x-private;q=0.977,de,*;q=0.000',4049 [4050 ('zh-Hant', 0.372), ('zh-CN-a-myExt-x-private', 0.977),4051 ('de', 1.0), ('*', 0.0)4052 ]4053 ),4054 (4055 ',\t foo \t;\t q=0.345,, bar ; Q=0.456 \t, ,\tcharlie \t,, ,',4056 [('foo', 0.345), ('bar', 0.456), ('charlie', 1.0)]4057 ),4058 # RFC 7230 Section 74059 ('foo,bar', [('foo', 1.0), ('bar', 1.0)]),4060 ('foo, bar,', [('foo', 1.0), ('bar', 1.0)]),4061 # RFC 7230 Errata ID: 41694062 ('foo , ,bar,charlie', [('foo', 1.0), ('bar', 1.0), ('charlie', 1.0)]),4063 ])4064 def test_parse__valid_header(self, value, expected_list):4065 returned = AcceptLanguage.parse(value=value)4066 list_of_returned = list(returned)4067 assert list_of_returned == expected_list4068class TestAcceptLanguageValidHeader(object):4069 @pytest.mark.parametrize('header_value', [4070 '',4071 ', da;q=0.2, en-gb;q=0.3 ',4072 ])4073 def test___init___invalid_header(self, header_value):4074 with pytest.raises(ValueError):4075 AcceptLanguageValidHeader(header_value=header_value)4076 def test___init___valid_header(self):4077 header_value = \4078 'zh-Hant;q=0.372,zh-CN-a-myExt-x-private;q=0.977,de,*;q=0.000'4079 instance = AcceptLanguageValidHeader(header_value=header_value)4080 assert instance.header_value == header_value4081 assert instance.parsed == [4082 ('zh-Hant', 0.372), ('zh-CN-a-myExt-x-private', 0.977),4083 ('de', 1.0), ('*', 0.0)4084 ]4085 assert instance._parsed_nonzero == [4086 ('zh-Hant', 0.372), ('zh-CN-a-myExt-x-private', 0.977),4087 ('de', 1.0)4088 ]4089 assert isinstance(instance, AcceptLanguage)4090 def test___add___None(self):4091 left_operand = AcceptLanguageValidHeader(header_value='en')4092 result = left_operand + None4093 assert isinstance(result, AcceptLanguageValidHeader)4094 assert result.header_value == left_operand.header_value4095 assert result is not left_operand4096 @pytest.mark.parametrize('right_operand', [4097 '',4098 [],4099 (),4100 {},4101 'en_gb',4102 ['en_gb'],4103 ('en_gb',),4104 {'en_gb': 1.0},4105 ',',4106 [','],4107 (',',),4108 {',': 1.0},4109 ])4110 def test___add___invalid_value(self, right_operand):4111 left_operand = AcceptLanguageValidHeader(header_value='en')4112 result = left_operand + right_operand4113 assert isinstance(result, AcceptLanguageValidHeader)4114 assert result.header_value == left_operand.header_value4115 assert result is not left_operand4116 @pytest.mark.parametrize('str_', ['', 'en_gb', ','])4117 def test___add___other_type_with_invalid___str__(self, str_,):4118 left_operand = AcceptLanguageValidHeader(header_value='en')4119 class Other(object):4120 def __str__(self):4121 return str_4122 right_operand = Other()4123 result = left_operand + right_operand4124 assert isinstance(result, AcceptLanguageValidHeader)4125 assert result.header_value == left_operand.header_value4126 assert result is not left_operand4127 @pytest.mark.parametrize('value, value_as_header', [4128 ('en-gb;q=0.5, fr;q=0, es', 'en-gb;q=0.5, fr;q=0, es'),4129 ([('en-gb', 0.5), ('fr', 0.0), 'es'], 'en-gb;q=0.5, fr;q=0, es'),4130 ((('en-gb', 0.5), ('fr', 0.0), 'es'), 'en-gb;q=0.5, fr;q=0, es'),4131 ({'en-gb': 0.5, 'fr': 0.0, 'es': 1.0}, 'es, en-gb;q=0.5, fr;q=0'),4132 ])4133 def test___add___valid_value(self, value, value_as_header):4134 header = ',\t ,de, zh-Hans;q=0.333,'4135 result = AcceptLanguageValidHeader(header_value=header) + value4136 assert isinstance(result, AcceptLanguageValidHeader)4137 assert result.header_value == header + ', ' + value_as_header4138 def test___add___other_type_with_valid___str__(self):4139 header = ',\t ,de, zh-Hans;q=0.333,'4140 class Other(object):4141 def __str__(self):4142 return 'en-gb;q=0.5, fr;q=0, es'4143 right_operand = Other()4144 result = AcceptLanguageValidHeader(header_value=header) + right_operand4145 assert isinstance(result, AcceptLanguageValidHeader)4146 assert result.header_value == header + ', ' + str(right_operand)4147 def test___add___AcceptLanguageValidHeader(self):4148 header1 = ',\t ,de, zh-Hans;q=0.333,'4149 header2 = ', ,fr;q=0, \tes;q=1,'4150 result = AcceptLanguageValidHeader(header_value=header1) + \4151 AcceptLanguageValidHeader(header_value=header2)4152 assert isinstance(result, AcceptLanguageValidHeader)4153 assert result.header_value == header1 + ', ' + header24154 def test___add___AcceptLanguageNoHeader(self):4155 valid_header_instance = AcceptLanguageValidHeader(header_value='es')4156 result = valid_header_instance + AcceptLanguageNoHeader()4157 assert isinstance(result, AcceptLanguageValidHeader)4158 assert result.header_value == valid_header_instance.header_value4159 assert result is not valid_header_instance4160 @pytest.mark.parametrize('header_value', ['', 'en_gb', ','])4161 def test___add___AcceptLanguageInvalidHeader(self, header_value):4162 valid_header_instance = AcceptLanguageValidHeader(4163 header_value='header',4164 )4165 result = valid_header_instance + AcceptLanguageInvalidHeader(4166 header_value=header_value,4167 )4168 assert isinstance(result, AcceptLanguageValidHeader)4169 assert result.header_value == valid_header_instance.header_value4170 assert result is not valid_header_instance4171 def test___bool__(self):4172 instance = AcceptLanguageValidHeader(header_value='valid-header')4173 returned = bool(instance)4174 assert returned is True4175 @pytest.mark.parametrize('header_value, offer', [4176 ('*', 'da'),4177 ('da', 'DA'),4178 ('en', 'en-gb'),4179 ('en-gb', 'en-gb'),4180 ('en-gb', 'en'),4181 ('en-gb', 'en_GB'),4182 ])4183 @pytest.mark.filterwarnings(IGNORE_CONTAINS)4184 def test___contains___in(self, header_value, offer):4185 instance = AcceptLanguageValidHeader(header_value=header_value)4186 assert offer in instance4187 @pytest.mark.parametrize('header_value, offer', [4188 ('en-gb', 'en-us'),4189 ('en-gb', 'fr-fr'),4190 ('en-gb', 'fr'),4191 ('en', 'fr-fr'),4192 ])4193 @pytest.mark.filterwarnings(IGNORE_CONTAINS)4194 def test___contains___not_in(self, header_value, offer):4195 instance = AcceptLanguageValidHeader(header_value=header_value)4196 assert offer not in instance4197 @pytest.mark.parametrize('header_value, expected_list', [4198 ('fr;q=0, jp;q=0', []),4199 ('en-gb, da', ['en-gb', 'da']),4200 ('en-gb;q=0.5, da;q=0.5', ['en-gb', 'da']),4201 (4202 'de;q=0.8, de-DE-1996;q=0.5, de-Deva;q=0, de-Latn-DE',4203 ['de-Latn-DE', 'de', 'de-DE-1996']4204 ),4205 # __iter__ is currently a simple filter for the ranges in the header4206 # with non-0 qvalues, and does not attempt to account for the special4207 # meanings of q=0 and *:4208 ('en-gb;q=0, *', ['*']),4209 ('de, de;q=0', ['de']),4210 ])4211 @pytest.mark.filterwarnings(IGNORE_ITER)4212 def test___iter__(self, header_value, expected_list):4213 instance = AcceptLanguageValidHeader(header_value=header_value)4214 assert list(instance) == expected_list4215 def test___radd___None(self):4216 right_operand = AcceptLanguageValidHeader(header_value='en')4217 result = None + right_operand4218 assert isinstance(result, AcceptLanguageValidHeader)4219 assert result.header_value == right_operand.header_value4220 assert result is not right_operand4221 @pytest.mark.parametrize('left_operand', [4222 '',4223 [],4224 (),4225 {},4226 'en_gb',4227 ['en_gb'],4228 ('en_gb',),4229 {'en_gb': 1.0},4230 ',',4231 [','],4232 (',',),4233 {',': 1.0},4234 ])4235 def test___radd___invalid_value(self, left_operand):4236 right_operand = AcceptLanguageValidHeader(header_value='en')4237 result = left_operand + right_operand4238 assert isinstance(result, AcceptLanguageValidHeader)4239 assert result.header_value == right_operand.header_value4240 assert result is not right_operand4241 @pytest.mark.parametrize('str_', ['', 'en_gb', ','])4242 def test___radd___other_type_with_invalid___str__(self, str_,):4243 right_operand = AcceptLanguageValidHeader(header_value='en')4244 class Other(object):4245 def __str__(self):4246 return str_4247 result = Other() + right_operand4248 assert isinstance(result, AcceptLanguageValidHeader)4249 assert result.header_value == right_operand.header_value4250 assert result is not right_operand4251 @pytest.mark.parametrize('value, value_as_header', [4252 ('en-gb;q=0.5, fr;q=0, es', 'en-gb;q=0.5, fr;q=0, es'),4253 ([('en-gb', 0.5), ('fr', 0.0), 'es'], 'en-gb;q=0.5, fr;q=0, es'),4254 ((('en-gb', 0.5), ('fr', 0.0), 'es'), 'en-gb;q=0.5, fr;q=0, es'),4255 ({'en-gb': 0.5, 'fr': 0.0, 'es': 1.0}, 'es, en-gb;q=0.5, fr;q=0'),4256 ])4257 def test___radd___valid_value(self, value, value_as_header):4258 right_operand = AcceptLanguageValidHeader(4259 header_value=',\t ,de, zh-Hans;q=0.333,',4260 )4261 result = value + right_operand4262 assert isinstance(result, AcceptLanguageValidHeader)4263 assert result.header_value == value_as_header + ', ' + \4264 right_operand.header_value4265 def test___radd___other_type_with_valid___str__(self):4266 right_operand = AcceptLanguageValidHeader(4267 header_value=',\t ,de, zh-Hans;q=0.333,',4268 )4269 class Other(object):4270 def __str__(self):4271 return 'en-gb;q=0.5, fr;q=0, es'4272 left_operand = Other()4273 result = left_operand + right_operand4274 assert isinstance(result, AcceptLanguageValidHeader)4275 assert result.header_value == str(left_operand) + ', ' + \4276 right_operand.header_value4277 def test___repr__(self):4278 instance = AcceptLanguageValidHeader(4279 header_value=',da;q=0.200,en-gb;q=0.300',4280 )4281 assert repr(instance) == \4282 "<AcceptLanguageValidHeader ('da;q=0.2, en-gb;q=0.3')>"4283 def test___str__(self):4284 header_value = \4285 ', \t,de;q=0.000 \t, es;q=1.000, zh, jp;q=0.210 ,'4286 instance = AcceptLanguageValidHeader(header_value=header_value)4287 assert str(instance) == 'de;q=0, es, zh, jp;q=0.21'4288 @pytest.mark.parametrize(4289 'header_value, language_tags, expected_returned',4290 [4291 # Example from RFC 4647, Section 3.44292 (4293 'de-de',4294 ['de', 'de-DE-1996', 'de-Deva', 'de-Latn-DE'],4295 [('de-DE-1996', 1.0)]4296 ),4297 # Empty `language_tags`4298 (4299 'a',4300 [],4301 []4302 ),4303 # No matches4304 (4305 'a, b',4306 ['c', 'd'],4307 []4308 ),4309 # Several ranges and tags, no matches4310 (4311 'a-b;q=0.9, c-d;q=0.5, e-f',4312 ('a', 'b', 'c', 'd', 'e', 'f'),4313 []4314 ),4315 # Case-insensitive match4316 (4317 'foO, BaR',4318 ['foo', 'bar'],4319 [('foo', 1.0), ('bar', 1.0)]4320 ),4321 # If a tag matches a non-'*' range with q=0, tag is filtered out4322 (4323 'b-c, a, b;q=0, d;q=0',4324 ['b-c', 'a', 'b-c-d', 'd-e-f'],4325 [('a', 1.0)]4326 ),4327 # Match if a range exactly equals a tag4328 (4329 'd-e-f',4330 ['a-b-c', 'd-e-f'],4331 [('d-e-f', 1.0)]4332 ),4333 # Match if a range exactly equals a prefix of the tag such that the4334 # first character following the prefix is '-'4335 (4336 'a-b-c-d, a-b-c-d-e, a-b-c-d-f-g-h',4337 ['a-b-c-d-f-g'],4338 [('a-b-c-d-f-g', 1.0)]4339 ),4340 # '*', when it is the only range in the header, matches everything4341 (4342 '*',4343 ['a', 'b'],4344 [('a', 1.0), ('b', 1.0)]4345 ),4346 # '*' range matches only tags not matched by any other range4347 (4348 '*;q=0.2, a;q=0.5, b',4349 ['a-a', 'b-a', 'c-a', 'd-a'],4350 [('b-a', 1.0), ('a-a', 0.5), ('c-a', 0.2), ('d-a', 0.2)]4351 ),4352 # '*' range without a qvalue gives a matched qvalue of 1.04353 (4354 'a;q=0.5, b, *',4355 ['a-a', 'b-a', 'c-a', 'd-a'],4356 [('b-a', 1.0), ('c-a', 1.0), ('d-a', 1.0), ('a-a', 0.5)]4357 ),4358 # The qvalue for the '*' range works the same way as qvalues for4359 # non-'*' ranges.4360 (4361 'a;q=0.5, *;q=0.9',4362 # (meaning: prefer anything other than 'a', with 'a' as a4363 # fallback)4364 ['a', 'b'],4365 [('b', 0.9), ('a', 0.5)]4366 ),4367 # More than one range matching the same tag: range with the highest4368 # qvalue is matched4369 (4370 'a-b-c;q=0.7, a;q=0.9, a-b;q=0.8',4371 ['a-b-c'],4372 [('a-b-c', 0.9)]4373 ),4374 # More than one range with the same qvalue matching the same tag:4375 # the range in an earlier position in the header is matched4376 (4377 'a-b-c;q=0.7, a;q=0.9, b;q=0.9, a-b;q=0.9',4378 ['a-b-c', 'b'],4379 [('a-b-c', 0.9), ('b', 0.9)]4380 ),4381 # The returned list of tuples is sorted in descending order of qvalue4382 (4383 'a;q=0.7, b;q=0.3, c, d;q=0.5',4384 ['d', 'c', 'b', 'a'],4385 [('c', 1.0), ('a', 0.7), ('d', 0.5), ('b', 0.3)]4386 ),4387 # When qvalues are the same, the tag whose matched range appears4388 # earlier in the header comes first4389 (4390 'a, c, b',4391 ['b', 'a', 'c'],4392 [('a', 1.0), ('c', 1.0), ('b', 1.0)]4393 ),4394 # When many tags match the same range (so same qvalue and same4395 # matched range position in header), they are returned in order of4396 # their position in the `language_tags` argument4397 (4398 'a',4399 ['a-b', 'a', 'a-b-c'],4400 [('a-b', 1.0), ('a', 1.0), ('a-b-c', 1.0)]4401 ),4402 # When a non-'*' range appears in the header more than once, we use4403 # the first one for matching and ignore the others4404 (4405 'a;q=0.5, c;q=0.6, b;q=0.7, c;q=0.9',4406 ['a', 'b', 'c'],4407 [('b', 0.7), ('c', 0.6), ('a', 0.5)]4408 ),4409 (4410 'a, b, c;q=0.5, c;q=0',4411 ['a-a', 'b-a', 'c-a'],4412 [('a-a', 1.0), ('b-a', 1.0), ('c-a', 0.5)]4413 ),4414 (4415 'a;q=0.5, c;q=0.9, b;q=0.9, c;q=0.9',4416 ['a', 'b', 'c'],4417 [('c', 0.9), ('b', 0.9), ('a', 0.5)]4418 ),4419 # When the '*' range appears in the header more than once, we use4420 # the first one for matching and ignore the others4421 (4422 'a;q=0.5, *;q=0.6, b;q=0.7, *;q=0.9',4423 ['a', 'b', 'c'],4424 [('b', 0.7), ('c', 0.6), ('a', 0.5)]4425 ),4426 (4427 'a, b, *;q=0.5, *;q=0',4428 ['a-a', 'b-a', 'c-a'],4429 [('a-a', 1.0), ('b-a', 1.0), ('c-a', 0.5)]4430 ),4431 (4432 'a;q=0.5, *;q=0.9, b;q=0.9, *;q=0.9',4433 ['a', 'b', 'c'],4434 [('c', 0.9), ('b', 0.9), ('a', 0.5)]4435 ),4436 # Both '*' and non-'*' ranges appearing more than once4437 (4438 'a-b;q=0.5, c-d, *, a-b, c-d;q=0.3, *;q=0',4439 ['a-b-c', 'c-d-e', 'e-f-g'],4440 [('c-d-e', 1.0), ('e-f-g', 1.0), ('a-b-c', 0.5)]4441 ),4442 ]4443 )4444 def test_basic_filtering(4445 self, header_value, language_tags, expected_returned,4446 ):4447 instance = AcceptLanguageValidHeader(header_value=header_value)4448 returned = instance.basic_filtering(language_tags=language_tags)4449 assert returned == expected_returned4450 @pytest.mark.parametrize(4451 'header_value, offers, default_match, expected_returned', [4452 ('bar, *;q=0', ['foo'], None, None),4453 ('en-gb, sr-Cyrl', ['sr-Cyrl', 'en-gb'], None, 'sr-Cyrl'),4454 ('en-gb, sr-Cyrl', ['en-gb', 'sr-Cyrl'], None, 'en-gb'),4455 ('en-gb, sr-Cyrl', [('sr-Cyrl', 0.5), 'en-gb'], None, 'en-gb'),4456 (4457 'en-gb, sr-Cyrl', [('sr-Cyrl', 0.5), ('en-gb', 0.4)], None,4458 'sr-Cyrl',4459 ),4460 ('en-gb, sr-Cyrl;q=0.5', ['en-gb', 'sr-Cyrl'], None, 'en-gb'),4461 ('en-gb;q=0.5, sr-Cyrl', ['en-gb', 'sr-Cyrl'], None, 'sr-Cyrl'),4462 (4463 'en-gb, sr-Cyrl;q=0.55, es;q=0.59', ['en-gb', 'sr-Cyrl'], None,4464 'en-gb',4465 ),4466 (4467 'en-gb;q=0.5, sr-Cyrl;q=0.586, es-419;q=0.597',4468 ['en-gb', 'es-419'], None, 'es-419',4469 ),4470 ]4471 )4472 @pytest.mark.filterwarnings(IGNORE_BEST_MATCH)4473 def test_best_match(4474 self, header_value, offers, default_match, expected_returned,4475 ):4476 instance = AcceptLanguageValidHeader(header_value=header_value)4477 returned = instance.best_match(4478 offers=offers, default_match=default_match,4479 )4480 assert returned == expected_returned4481 def test_lookup_default_tag_and_default_cannot_both_be_None(self):4482 instance = AcceptLanguageValidHeader(header_value='valid-header')4483 with pytest.raises(TypeError):4484 instance.lookup(4485 language_tags=['tag'],4486 default_range='language-range',4487 default_tag=None,4488 default=None,4489 )4490 def test_lookup_default_range_cannot_be_asterisk(self):4491 instance = AcceptLanguageValidHeader(header_value='valid-header')4492 with pytest.raises(ValueError):4493 instance.lookup(4494 language_tags=['tag'],4495 default_range='*',4496 default_tag='default-tag',4497 default=None,4498 )4499 @pytest.mark.parametrize(4500 (4501 'header_value, language_tags, default_range, default_tag, default'4502 ', expected'4503 ),4504 [4505 # Each language range in the header is considered in turn, in4506 # descending order of qvalue4507 (4508 'aA;q=0.3, Bb, cC;q=0.7',4509 ['Aa', 'bB', 'Cc'],4510 None, 'default-tag', None,4511 'bB',4512 ),4513 # For ranges with the same qvalue, position in header is the4514 # tiebreaker.4515 (4516 'bB-Cc;q=0.8, aA;q=0.9, Bb;q=0.9',4517 ['bb', 'aa'],4518 None, 'default-tag', None,4519 'aa',4520 ),4521 # Each language range represents the most specific tag that is an4522 # acceptable match. Examples from RFC 4647, section 3.4, first4523 # paragraph:4524 (4525 'de-ch',4526 ['de-CH-1996', 'de-CH', 'de'],4527 None, 'default-tag', None,4528 'de-CH',4529 ),4530 (4531 'de-ch',4532 ['de-CH-1996', 'de'],4533 None, 'default-tag', None,4534 'de',4535 ),4536 # The language range is progressively truncated from the end until4537 # a matching language tag is located. From the example of a Lookup4538 # Fallback Pattern in RFC 4647, section 3.4:4539 (4540 'zh-Hant-CN-x-private1-private2',4541 [4542 'zh-Hant-CN-x-private1-private2',4543 'zh-Hant-CN-x-private1',4544 'zh-Hant-CN-x',4545 'zh-Hant-CN',4546 'zh-Hant',4547 'zh',4548 ],4549 None, 'default-tag', None,4550 'zh-Hant-CN-x-private1-private2',4551 ),4552 (4553 'zh-Hant-CN-x-private1-private2',4554 [4555 'zh-Hant-CN-x-private1',4556 'zh-Hant-CN-x',4557 'zh-Hant-CN',4558 'zh-Hant',4559 'zh',4560 ],4561 None, 'default-tag', None,4562 'zh-Hant-CN-x-private1',4563 ),4564 (4565 'zh-Hant-CN-x-private1-private2',4566 [4567 'zh-Hant-CN-x',4568 'zh-Hant-CN',4569 'zh-Hant',4570 'zh',4571 ],4572 None, 'default-tag', None,4573 'zh-Hant-CN',4574 ),4575 (4576 'zh-Hant-CN-x-private1-private2',4577 [4578 'zh-Hant-CN',4579 'zh-Hant',4580 'zh',4581 ],4582 None, 'default-tag', None,4583 'zh-Hant-CN',4584 ),4585 (4586 'zh-Hant-CN-x-private1-private2',4587 [4588 'zh-Hant',4589 'zh',4590 ],4591 None, 'default-tag', None,4592 'zh-Hant',4593 ),4594 (4595 'zh-Hant-CN-x-private1-private2',4596 ['zh'],4597 None, 'default-tag', None,4598 'zh',4599 ),4600 (4601 'zh-Hant-CN-x-private1-private2',4602 ['some-other-tag-1', 'some-other-tag-2'],4603 None, 'default-tag', None,4604 'default-tag',4605 ),4606 # Further tests to check that single-letter or -digit subtags are4607 # removed at the same time as their closest trailing subtag:4608 (4609 'AA-T-subtag',4610 ['Aa-t', 'aA'],4611 None, 'default-tag', None,4612 'aA',4613 ),4614 (4615 'AA-1-subtag',4616 ['aa-1', 'aA'],4617 None, 'default-tag', None,4618 'aA',4619 ),4620 (4621 'Aa-P-subtag-8-subtag',4622 ['Aa-p-subtag-8', 'Aa-p', 'aA'],4623 None, 'default-tag', None,4624 'aA',4625 ),4626 (4627 'aA-3-subTag-C-subtag',4628 ['aA-3-subtag-c', 'aA-3', 'aA'],4629 None, 'default-tag', None,4630 'aA',4631 ),4632 # Test that single-letter or -digit subtag in first position works4633 # as expected4634 (4635 'T-subtag',4636 ['t-SubTag', 'another'],4637 None, 'default-tag', None,4638 't-SubTag',4639 ),4640 (4641 'T-subtag',4642 ['another'],4643 None, 'default-tag', None,4644 'default-tag',4645 ),4646 # If the language range "*" is followed by other language ranges,4647 # it is skipped.4648 (4649 '*, Aa-aA-AA',4650 ['bb', 'aA'],4651 None, 'default-tag', None,4652 'aA',4653 ),4654 # If the language range "*" is the only one in the header, lookup4655 # proceeds to the default arguments.4656 (4657 '*',4658 ['bb', 'aa'],4659 None, 'default-tag', None,4660 'default-tag',4661 ),4662 # If no other language range follows the "*" in the header, lookup4663 # proceeds to the default arguments.4664 (4665 'dd, cc, *',4666 ['bb', 'aa'],4667 None, 'default-tag', None,4668 'default-tag',4669 ),4670 # If a non-'*' range has q=0, any tag that matches the range4671 # exactly (without subtag truncation) is not acceptable.4672 (4673 'aa, bB-Cc-DD;q=0, bB-Cc, cc',4674 ['bb', 'bb-Cc-DD', 'bb-cC-dd', 'Bb-cc', 'bb-cC-dd'],4675 None, 'default-tag', None,4676 'Bb-cc',4677 ),4678 # ;q=0 and ;q={not 0} both in header: q=0 takes precedence and4679 # makes the exact match not acceptable, but the q={not 0} means4680 # that tags can still match after subtag truncation.4681 (4682 'aa, bB-Cc-DD;q=0.9, cc, Bb-cC-dD;q=0',4683 ['bb', 'Bb-Cc', 'Bb-cC-dD'],4684 None, 'default-tag', None,4685 'Bb-Cc',4686 ),4687 # If none of the ranges in the header match any of the language4688 # tags, and the `default_range` argument is not None and does not4689 # match any q=0 range in the header, we search through it by4690 # progressively truncating from the end, as we do with the ranges4691 # in the header. Example from RFC 4647, section 3.4.1:4692 (4693 'fr-FR, zh-Hant',4694 [4695 'fr-FR',4696 'fr',4697 'zh-Hant',4698 'zh',4699 'ja-JP',4700 'ja',4701 ],4702 'ja-JP', 'default-tag', None,4703 'fr-FR',4704 ),4705 (4706 'fr-FR, zh-Hant',4707 [4708 'fr',4709 'zh-Hant',4710 'zh',4711 'ja-JP',4712 'ja',4713 ],4714 'ja-JP', 'default-tag', None,4715 'fr',4716 ),4717 (4718 'fr-FR, zh-Hant',4719 [4720 'zh-Hant',4721 'zh',4722 'ja-JP',4723 'ja',4724 ],4725 'ja-JP', 'default-tag', None,4726 'zh-Hant',4727 ),4728 (4729 'fr-FR, zh-Hant',4730 [4731 'zh',4732 'ja-JP',4733 'ja',4734 ],4735 'ja-JP', 'default-tag', None,4736 'zh',4737 ),4738 (4739 'fr-FR, zh-Hant',4740 [4741 'ja-JP',4742 'ja',4743 ],4744 'ja-JP', 'default-tag', None,4745 'ja-JP',4746 ),4747 (4748 'fr-FR, zh-Hant',4749 ['ja'],4750 'ja-JP', 'default-tag', None,4751 'ja',4752 ),4753 (4754 'fr-FR, zh-Hant',4755 ['some-other-tag-1', 'some-other-tag-2'],4756 'ja-JP', 'default-tag', None,4757 'default-tag',4758 ),4759 # If none of the ranges in the header match the language tags, the4760 # `default_range` argument is not None, and there is a '*;q=0'4761 # range in the header, then the `default_range` and its substrings4762 # from subtag truncation are not acceptable.4763 (4764 'aa-bb, cc-dd, *;q=0',4765 ['ee-ff', 'ee'],4766 'ee-ff', None, 'default',4767 'default',4768 ),4769 # If none of the ranges in the header match the language tags, the4770 # `default_range` argument is not None, and the argument exactly4771 # matches a non-'*' range in the header with q=0 (without fallback4772 # subtag truncation), then the `default_range` itself is not4773 # acceptable...4774 (4775 'aa-bb, cc-dd, eE-Ff;q=0',4776 ['Ee-fF'],4777 'EE-FF', 'default-tag', None,4778 'default-tag',4779 ),4780 # ...but it should still be searched with subtag truncation,4781 # because its substrings other than itself are still acceptable:4782 (4783 'aa-bb, cc-dd, eE-Ff-Gg;q=0',4784 ['Ee', 'Ee-fF-gG', 'Ee-fF'],4785 'EE-FF-GG', 'default-tag', None,4786 'Ee-fF',4787 ),4788 (4789 'aa-bb, cc-dd, eE-Ff-Gg;q=0',4790 ['Ee-fF-gG', 'Ee'],4791 'EE-FF-GG', 'default-tag', None,4792 'Ee',4793 ),4794 # If `default_range` only has one subtag, then no subtag truncation4795 # is possible, and we proceed to `default-tag`:4796 (4797 'aa-bb, cc-dd, eE;q=0',4798 ['Ee'],4799 'EE', 'default-tag', None,4800 'default-tag',4801 ),4802 # If the `default_range` argument would only match a non-'*' range4803 # in the header with q=0 exactly if the `default_range` had subtags4804 # from the end truncated, then it is acceptable, and we attempt to4805 # match it with the language tags using subtag truncation. However,4806 # the tag equivalent of the range with q=0 would be considered not4807 # acceptable and ruled out, if we reach it during the subtag4808 # truncation search.4809 (4810 'aa-bb, cc-dd, eE-Ff;q=0',4811 ['Ee-fF', 'Ee-fF-33', 'ee'],4812 'EE-FF-33', 'default-tag', None,4813 'Ee-fF-33',4814 ),4815 (4816 'aa-bb, cc-dd, eE-Ff;q=0',4817 ['Ee-fF', 'eE'],4818 'EE-FF-33', 'default-tag', None,4819 'eE',4820 ),4821 # If none of the ranges in the header match, the `default_range`4822 # argument is None or does not match, and the `default_tag`4823 # argument is not None and does not match any range in the header4824 # with q=0, then the `default_tag` argument is returned.4825 (4826 'aa-bb, cc-dd',4827 ['ee-ff', 'ee'],4828 None, 'default-tag', None,4829 'default-tag',4830 ),4831 (4832 'aa-bb, cc-dd',4833 ['ee-ff', 'ee'],4834 'gg-hh', 'default-tag', None,4835 'default-tag',4836 ),4837 # If none of the ranges in the header match, the `default_range`4838 # argument is None or does not match, the `default_tag` argument is4839 # not None, and there is a '*' range in the header with q=0, then4840 # the `default_tag` argument is not acceptable.4841 (4842 'aa-bb, cc-dd, *;q=0',4843 ['ee-ff', 'ee'],4844 'gg-hh', 'ii-jj', 'default',4845 'default',4846 ),4847 # If none of the ranges in the header match, the `default_range`4848 # argument is None or does not match, the `default_tag` argument is4849 # not None and matches a non-'*' range in the header with q=04850 # exactly, then the `default_tag` argument is not acceptable.4851 (4852 'aa-bb, cc-dd, iI-jJ;q=0',4853 ['ee-ff', 'ee'],4854 'gg-hh', 'Ii-Jj', 'default',4855 'default',4856 ),4857 # If none of the ranges in the header match, the `default_range`4858 # argument is None or does not match, and the `default_tag`4859 # argument is None, then we proceed to the `default` argument.4860 (4861 'aa-bb, cc-dd',4862 ['ee-ff', 'ee'],4863 None, None, 'default',4864 'default',4865 ),4866 (4867 'aa-bb, cc-dd',4868 ['ee-ff', 'ee'],4869 'gg-hh', None, 'default',4870 'default',4871 ),4872 # If we fall back to the `default` argument, and it is not a4873 # callable, the argument itself is returned.4874 (4875 'aa',4876 ['bb'],4877 None, None, 0,4878 0,4879 ),4880 (4881 'Aa, cC;q=0',4882 ['bb'],4883 'aA-Cc', 'Cc', ['non-callable object'],4884 ['non-callable object'],4885 ),4886 # If we fall back to the `default` argument, and it is a callable,4887 # it is called, and the callable's return value is returned by the4888 # method.4889 (4890 'aa',4891 ['bb'],4892 None, None, lambda: 'callable called',4893 'callable called',4894 ),4895 (4896 'Aa, cc;q=0',4897 ['bb'],4898 'aA-cC', 'cc', lambda: 'callable called',4899 'callable called',4900 ),4901 # Even if the 'default' argument is a str that matches a q=0 range4902 # in the header, it is still returned.4903 (4904 'aa, *;q=0',4905 ['bb'],4906 None, None, 'cc',4907 'cc',4908 ),4909 (4910 'aa, cc;q=0',4911 ['bb'],4912 None, None, 'cc',4913 'cc',4914 ),4915 # If the `default_tag` argument is not acceptable because of a q=04916 # range in the header, and the `default` argument is None, then4917 # None is returned.4918 (4919 'aa, Bb;q=0',4920 ['cc'],4921 None, 'bB', None,4922 None,4923 ),4924 (4925 'aa, *;q=0',4926 ['cc'],4927 None, 'bb', None,4928 None,4929 ),4930 # Test that method works with empty `language_tags`:4931 (4932 'range',4933 [],4934 None, 'default-tag', None,4935 'default-tag',4936 ),4937 # Test that method works with empty `default_range`:4938 (4939 'range',4940 [],4941 '', 'default-tag', None,4942 'default-tag',4943 ),4944 (4945 'range',4946 ['tag'],4947 '', 'default-tag', None,4948 'default-tag',4949 ),4950 # Test that method works with empty `default_tag`:4951 (4952 'range',4953 [],4954 '', '', None,4955 '',4956 ),4957 (4958 'range',4959 ['tag'],4960 'default-range', '', None,4961 '',4962 ),4963 ]4964 )4965 def test_lookup(4966 self, header_value, language_tags, default_range, default_tag,4967 default, expected,4968 ):4969 instance = AcceptLanguageValidHeader(header_value=header_value)4970 returned = instance.lookup(4971 language_tags=language_tags,4972 default_range=default_range,4973 default_tag=default_tag,4974 default=default,4975 )4976 assert returned == expected4977 @pytest.mark.parametrize('header_value, offer, expected_returned', [4978 ('en-gb', 'en-gb', 1),4979 ('en-gb;q=0.5', 'en-gb', 0.5),4980 ('en-gb', 'sr-Cyrl', None),4981 ])4982 @pytest.mark.filterwarnings(IGNORE_QUALITY)4983 def test_quality(self, header_value, offer, expected_returned):4984 instance = AcceptLanguageValidHeader(header_value=header_value)4985 returned = instance.quality(offer=offer)4986 assert returned == expected_returned4987class TestAcceptLanguageNoHeader(object):4988 def test___init__(self):4989 instance = AcceptLanguageNoHeader()4990 assert instance.header_value is None4991 assert instance.parsed is None4992 assert instance._parsed_nonzero is None4993 assert isinstance(instance, AcceptLanguage)4994 def test___add___None(self):4995 instance = AcceptLanguageNoHeader()4996 result = instance + None4997 assert isinstance(result, AcceptLanguageNoHeader)4998 assert result is not instance4999 @pytest.mark.parametrize('right_operand', [5000 '',5001 [],5002 (),5003 {},5004 'en_gb',5005 ['en_gb'],5006 ('en_gb',),5007 {'en_gb': 1.0},5008 ])5009 def test___add___invalid_value(self, right_operand):5010 left_operand = AcceptLanguageNoHeader()5011 result = left_operand + right_operand5012 assert isinstance(result, AcceptLanguageNoHeader)5013 assert result is not left_operand5014 @pytest.mark.parametrize('str_', ['', 'en_gb'])5015 def test___add___other_type_with_invalid___str__(self, str_,):5016 left_operand = AcceptLanguageNoHeader()5017 class Other(object):5018 def __str__(self):5019 return str_5020 result = left_operand + Other()5021 assert isinstance(result, AcceptLanguageNoHeader)5022 assert result is not left_operand5023 @pytest.mark.parametrize('value, value_as_header', [5024 ('en-gb;q=0.5, fr;q=0, es', 'en-gb;q=0.5, fr;q=0, es'),5025 ([('en-gb', 0.5), ('fr', 0.0), 'es'], 'en-gb;q=0.5, fr;q=0, es'),5026 ((('en-gb', 0.5), ('fr', 0.0), 'es'), 'en-gb;q=0.5, fr;q=0, es'),5027 ({'en-gb': 0.5, 'fr': 0.0, 'es': 1.0}, 'es, en-gb;q=0.5, fr;q=0'),5028 ])5029 def test___add___valid_value(self, value, value_as_header):5030 result = AcceptLanguageNoHeader() + value5031 assert isinstance(result, AcceptLanguageValidHeader)5032 assert result.header_value == value_as_header5033 def test___add___other_type_with_valid___str__(self):5034 class Other(object):5035 def __str__(self):5036 return 'en-gb;q=0.5, fr;q=0, es'5037 right_operand = Other()5038 result = AcceptLanguageNoHeader() + right_operand5039 assert isinstance(result, AcceptLanguageValidHeader)5040 assert result.header_value == str(right_operand)5041 def test___add___AcceptLanguageValidHeader(self):5042 right_operand = AcceptLanguageValidHeader(5043 header_value=', ,fr;q=0, \tes;q=1,',5044 )5045 result = AcceptLanguageNoHeader() + right_operand5046 assert isinstance(result, AcceptLanguageValidHeader)5047 assert result.header_value == right_operand.header_value5048 def test___add___AcceptLanguageNoHeader(self):5049 left_operand = AcceptLanguageNoHeader()5050 right_operand = AcceptLanguageNoHeader()5051 result = left_operand + right_operand5052 assert isinstance(result, AcceptLanguageNoHeader)5053 assert result is not left_operand5054 assert result is not right_operand5055 @pytest.mark.parametrize('invalid_header_value', ['', 'en_gb'])5056 def test___add___AcceptLanguageInvalidHeader(self, invalid_header_value):5057 left_operand = AcceptLanguageNoHeader()5058 result = left_operand + AcceptLanguageInvalidHeader(5059 header_value=invalid_header_value,5060 )5061 assert isinstance(result, AcceptLanguageNoHeader)5062 assert result is not left_operand5063 def test___bool__(self):5064 instance = AcceptLanguageNoHeader()5065 returned = bool(instance)5066 assert returned is False5067 @pytest.mark.filterwarnings(IGNORE_CONTAINS)5068 def test___contains__(self):5069 instance = AcceptLanguageNoHeader()5070 returned = ('any-tag' in instance)5071 assert returned is True5072 @pytest.mark.filterwarnings(IGNORE_ITER)5073 def test___iter__(self):5074 instance = AcceptLanguageNoHeader()5075 returned = list(instance)5076 assert returned == []5077 def test___radd___None(self):5078 right_operand = AcceptLanguageNoHeader()5079 result = None + right_operand5080 assert isinstance(result, AcceptLanguageNoHeader)5081 assert result is not right_operand5082 @pytest.mark.parametrize('left_operand', [5083 '',5084 [],5085 (),5086 {},5087 'en_gb',5088 ['en_gb'],5089 ('en_gb',),5090 {'en_gb': 1.0},5091 ])5092 def test___radd___invalid_value(self, left_operand):5093 right_operand = AcceptLanguageNoHeader()5094 result = left_operand + right_operand5095 assert isinstance(result, AcceptLanguageNoHeader)5096 assert result is not right_operand5097 @pytest.mark.parametrize('str_', ['', 'en_gb', ','])5098 def test___radd___other_type_with_invalid___str__(self, str_,):5099 right_operand = AcceptLanguageNoHeader()5100 class Other(object):5101 def __str__(self):5102 return str_5103 result = Other() + right_operand5104 assert isinstance(result, AcceptLanguageNoHeader)5105 assert result is not right_operand5106 @pytest.mark.parametrize('value, value_as_header', [5107 ('en-gb;q=0.5, fr;q=0, es', 'en-gb;q=0.5, fr;q=0, es'),5108 ([('en-gb', 0.5), ('fr', 0.0), 'es'], 'en-gb;q=0.5, fr;q=0, es'),5109 ((('en-gb', 0.5), ('fr', 0.0), 'es'), 'en-gb;q=0.5, fr;q=0, es'),5110 ({'en-gb': 0.5, 'fr': 0.0, 'es': 1.0}, 'es, en-gb;q=0.5, fr;q=0'),5111 ])5112 def test___radd___valid_value(self, value, value_as_header):5113 result = value + AcceptLanguageNoHeader()5114 assert isinstance(result, AcceptLanguageValidHeader)5115 assert result.header_value == value_as_header5116 def test___radd___other_type_with_valid___str__(self):5117 class Other(object):5118 def __str__(self):5119 return 'en-gb;q=0.5, fr;q=0, es'5120 left_operand = Other()5121 result = left_operand + AcceptLanguageNoHeader()5122 assert isinstance(result, AcceptLanguageValidHeader)5123 assert result.header_value == str(left_operand)5124 def test___repr__(self):5125 instance = AcceptLanguageNoHeader()5126 assert repr(instance) == '<AcceptLanguageNoHeader>'5127 def test___str__(self):5128 instance = AcceptLanguageNoHeader()5129 assert str(instance) == '<no header in request>'5130 def test_basic_filtering(self):5131 instance = AcceptLanguageNoHeader()5132 returned = instance.basic_filtering(language_tags=['tag1', 'tag2'])5133 assert returned == []5134 @pytest.mark.parametrize('offers, default_match, expected_returned', [5135 (['foo', 'bar'], None, 'foo'),5136 ([('foo', 1), ('bar', 0.5)], None, 'foo'),5137 ([('foo', 0.5), ('bar', 1)], None, 'bar'),5138 ([('foo', 0.5), 'bar'], None, 'bar'),5139 ([('foo', 0.5), 'bar'], object(), 'bar'),5140 ([], 'fallback', 'fallback'),5141 ])5142 @pytest.mark.filterwarnings(IGNORE_BEST_MATCH)5143 def test_best_match(self, offers, default_match, expected_returned):5144 instance = AcceptLanguageNoHeader()5145 returned = instance.best_match(5146 offers=offers, default_match=default_match,5147 )5148 assert returned == expected_returned5149 def test_lookup_default_tag_and_default_cannot_both_be_None(self):5150 instance = AcceptLanguageNoHeader()5151 with pytest.raises(TypeError):5152 instance.lookup(default_tag=None, default=None)5153 @pytest.mark.parametrize('default_tag, default, expected', [5154 # If `default_tag` is not None, it is returned.5155 ('default-tag', 'default', 'default-tag'),5156 # If `default_tag` is None, we proceed to the `default` argument. If5157 # `default` is not a callable, the argument itself is returned.5158 (None, 0, 0),5159 # If `default` is a callable, it is called, and the callable's return5160 # value is returned by the method.5161 (None, lambda: 'callable called', 'callable called'),5162 ])5163 def test_lookup(self, default_tag, default, expected):5164 instance = AcceptLanguageNoHeader()5165 returned = instance.lookup(5166 default_tag=default_tag,5167 default=default,5168 )5169 assert returned == expected5170 @pytest.mark.filterwarnings(IGNORE_QUALITY)5171 def test_quality(self):5172 instance = AcceptLanguageNoHeader()5173 returned = instance.quality(offer='any-tag')5174 assert returned == 1.05175class TestAcceptLanguageInvalidHeader(object):5176 def test___init__(self):5177 header_value = 'invalid header'5178 instance = AcceptLanguageInvalidHeader(header_value=header_value)5179 assert instance.header_value == header_value5180 assert instance.parsed is None5181 assert instance._parsed_nonzero is None5182 assert isinstance(instance, AcceptLanguage)5183 def test___add___None(self):5184 instance = AcceptLanguageInvalidHeader(header_value='')5185 result = instance + None5186 assert isinstance(result, AcceptLanguageNoHeader)5187 @pytest.mark.parametrize('right_operand', [5188 '',5189 [],5190 (),5191 {},5192 'en_gb',5193 ['en_gb'],5194 ('en_gb',),5195 {'en_gb': 1.0},5196 ])5197 def test___add___invalid_value(self, right_operand):5198 result = AcceptLanguageInvalidHeader(header_value='') + right_operand5199 assert isinstance(result, AcceptLanguageNoHeader)5200 @pytest.mark.parametrize('str_', ['', 'en_gb'])5201 def test___add___other_type_with_invalid___str__(self, str_):5202 class Other(object):5203 def __str__(self):5204 return str_5205 result = AcceptLanguageInvalidHeader(header_value='') + Other()5206 assert isinstance(result, AcceptLanguageNoHeader)5207 @pytest.mark.parametrize('value', [5208 'en',5209 ['en'],5210 ('en',),5211 {'en': 1.0},5212 ])5213 def test___add___valid_header_value(self, value):5214 result = AcceptLanguageInvalidHeader(header_value='') + value5215 assert isinstance(result, AcceptLanguageValidHeader)5216 assert result.header_value == 'en'5217 def test___add___other_type_valid_header_value(self):5218 class Other(object):5219 def __str__(self):5220 return 'en'5221 result = AcceptLanguageInvalidHeader(header_value='') + Other()5222 assert isinstance(result, AcceptLanguageValidHeader)5223 assert result.header_value == 'en'5224 def test___add___AcceptLanguageValidHeader(self):5225 right_operand = AcceptLanguageValidHeader(header_value='en')5226 result = AcceptLanguageInvalidHeader(header_value='') + right_operand5227 assert isinstance(result, AcceptLanguageValidHeader)5228 assert result.header_value == right_operand.header_value5229 assert result is not right_operand5230 def test___add___AcceptLanguageNoHeader(self):5231 right_operand = AcceptLanguageNoHeader()5232 result = AcceptLanguageInvalidHeader(header_value='') + right_operand5233 assert isinstance(result, AcceptLanguageNoHeader)5234 assert result is not right_operand5235 def test___add___AcceptLanguageInvalidHeader(self):5236 result = AcceptLanguageInvalidHeader(header_value='') + \5237 AcceptLanguageInvalidHeader(header_value='')5238 assert isinstance(result, AcceptLanguageNoHeader)5239 def test___bool__(self):5240 instance = AcceptLanguageInvalidHeader(header_value='')5241 returned = bool(instance)5242 assert returned is False5243 @pytest.mark.filterwarnings(IGNORE_CONTAINS)5244 def test___contains__(self):5245 instance = AcceptLanguageInvalidHeader(header_value='')5246 returned = ('any-tag' in instance)5247 assert returned is True5248 @pytest.mark.filterwarnings(IGNORE_ITER)5249 def test___iter__(self):5250 instance = AcceptLanguageInvalidHeader(header_value='')5251 returned = list(instance)5252 assert returned == []5253 def test___radd___None(self):5254 instance = AcceptLanguageInvalidHeader(header_value='')5255 result = None + instance5256 assert isinstance(result, AcceptLanguageNoHeader)5257 @pytest.mark.parametrize('left_operand', [5258 '',5259 [],5260 (),5261 {},5262 'en_gb',5263 ['en_gb'],5264 ('en_gb',),5265 {'en_gb': 1.0},5266 ])5267 def test___radd___invalid_value(self, left_operand):5268 result = left_operand + AcceptLanguageInvalidHeader(header_value='')5269 assert isinstance(result, AcceptLanguageNoHeader)5270 @pytest.mark.parametrize('str_', ['', 'en_gb'])5271 def test___radd___other_type_with_invalid___str__(self, str_):5272 class Other(object):5273 def __str__(self):5274 return str_5275 result = Other() + AcceptLanguageInvalidHeader(header_value='')5276 assert isinstance(result, AcceptLanguageNoHeader)5277 @pytest.mark.parametrize('value', [5278 'en',5279 ['en'],5280 ('en',),5281 {'en': 1.0},5282 ])5283 def test___radd___valid_header_value(self, value):5284 result = value + AcceptLanguageInvalidHeader(header_value='')5285 assert isinstance(result, AcceptLanguageValidHeader)5286 assert result.header_value == 'en'5287 def test___radd___other_type_valid_header_value(self):5288 class Other(object):5289 def __str__(self):5290 return 'en'5291 result = Other() + AcceptLanguageInvalidHeader(header_value='')5292 assert isinstance(result, AcceptLanguageValidHeader)5293 assert result.header_value == 'en'5294 def test___repr__(self):5295 instance = AcceptLanguageInvalidHeader(header_value='\x00')5296 assert repr(instance) == '<AcceptLanguageInvalidHeader>'5297 def test___str__(self):5298 instance = AcceptLanguageInvalidHeader(header_value="invalid header")5299 assert str(instance) == '<invalid header value>'5300 def test_basic_filtering(self):5301 instance = AcceptLanguageInvalidHeader(header_value='')...
get_constant_data.py
Source:get_constant_data.py
1import urllib.request2import urllib.parse3from bs4 import BeautifulSoup, Comment4import json5import logging6from logging.handlers import TimedRotatingFileHandler7import sys8import time9import math10import socket11import re12import getopt13import datetime14import threading15import lxml16import cchardet17import ssl18league_totals_url = "https://www.hockey-reference.com/{}/NHL_{}_{}.html"19current_year_stats_url = "https://www.hockey-reference.com/{}/NHL_{}.html"20max_request_retries = 321retry_failure_delay = 322request_headers = {23 "User-Agent" : "NHLCompareRedditBot"24}25logname = "nhl-constants.log"26logger = logging.getLogger("nhl-constants")27logger.setLevel(logging.INFO)28formatter = logging.Formatter(fmt='%(asctime)s %(levelname)-8s %(message)s', datefmt='%Y-%m-%d %H:%M:%S')29handler = TimedRotatingFileHandler(logname, when="midnight", interval=1)30handler.suffix = "%Y%m%d"31handler.setFormatter(formatter)32logger.addHandler(handler)33streamhandler = logging.StreamHandler(sys.stdout)34streamhandler.setLevel(logging.DEBUG)35logger.addHandler(streamhandler)36start_year = 191737end_year = 202138current_year_playoffs_started = False39year_games_played = [40 {41 "start_year" : start_year,42 "end_year" : 1924,43 "roster" : 944 },45 {46 "start_year" : 1925,47 "end_year" : 1928,48 "roster" : 1249 },50 {51 "start_year" : 1929,52 "end_year" : 1931,53 "roster" : 1554 },55 {56 "start_year" : 1932,57 "end_year" : 1937,58 "roster" : 1459 },60 {61 "start_year" : 1938,62 "end_year" : 1941,63 "roster" : 1564 },65 {66 "start_year" : 1942,67 "end_year" : 1948,68 "roster" : 1469 },70 {71 "start_year" : 1949,72 "end_year" : 1950,73 "roster" : 1774 },75 {76 "start_year" : 1951,77 "end_year" : 1951,78 "roster" : 1579 },80 {81 "start_year" : 1952,82 "end_year" : 1952,83 "roster" : 15.584 },85 {86 "start_year" : 1953,87 "end_year" : 1953,88 "roster" : 1689 },90 {91 "start_year" : 1954,92 "end_year" : 1959,93 "roster" : 1794 },95 {96 "start_year" : 1960,97 "end_year" : 1970,98 "roster" : 1699 },100 {101 "start_year" : 1971,102 "end_year" : 1981,103 "roster" : 17104 },105 {106 "start_year" : 1982,107 "end_year" : end_year,108 "roster" : 18109 }110]111ssl._create_default_https_context = ssl._create_unverified_context112def main():113 year_short = "y"114 year_long = "year"115 try:116 options = getopt.getopt(sys.argv[1:], year_short + ":", [year_long + "="])[0]117 except getopt.GetoptError as err:118 logger.error("Encountered error \"" + str(err) + "\" parsing arguments")119 return120 year = None121 for opt, arg in options:122 if opt in ("-" + year_short, "--" + year_long):123 year = int(arg.strip())124 totals = None125 if year:126 with open("yearly_totals.json", "r") as file:127 totals = json.load(file)128 get_totals(year, totals)129 else:130 totals = get_totals(None, None)131 with open("yearly_totals.json", "w") as file:132 file.write(json.dumps(totals, indent=4, sort_keys=True))133def get_totals(specific_year, totals):134 logger.info("Getting league total data for year " + str(specific_year))135 format_strs = {136 "Skater" : "skaters",137 "Goalie" : "goalies"138 }139 if not totals:140 totals = {141 "Standard" : {142 "Skater" : {143 "F" : {},144 "D" : {}145 },146 "Goalie" : {147 "G" : {}148 },149 "TOT" : {}150 },151 "Playoffs" : {152 "Skater" : {153 "F" : {},154 "D" : {}155 },156 "Goalie" : {157 "G" : {}158 },159 "TOT" : {}160 }161 }162 elif specific_year:163 for over_key in totals:164 for key in totals[over_key]:165 if key == "TOT":166 totals[over_key][key][str(specific_year)] = {}167 else:168 for pos in totals[over_key][key]:169 totals[over_key][key][pos][str(specific_year)] = {}170 headers_to_read = {171 "Skater" : {172 "GP",173 "G",174 "A",175 "PTS",176 "+/-",177 "PIM",178 "PPG",179 "SHG",180 "PPA",181 "S",182 "TOI"183 },184 "Goalie" : {185 "GP",186 "W",187 "L",188 "T/O",189 "GA",190 "SA",191 "SV",192 "SO",193 "TOI",194 "G",195 "A",196 "PTS",197 "PIM"198 }199 }200 years = None201 if specific_year:202 years = [specific_year]203 else:204 years = range(start_year, end_year + 1)205 team_map_by_year = {}206 for over_key in totals:207 logger.info("Getting league total game data for " + over_key)208 current_percent = 10209 count = 0210 for year in years:211 if over_key == "Playoffs" and year == end_year and not current_year_playoffs_started:212 logger.info("Skipping current year " + str(year) + " as playoffs have not stared yet")213 continue214 team_map_by_year_val = calculate_year_games_by_team(year, over_key == "Playoffs")215 if not over_key in team_map_by_year:216 team_map_by_year[over_key] = {}217 team_map_by_year[over_key][str(year)] = team_map_by_year_val218 219 count += 1220 percent_complete = 100 * (count / len(years))221 if not specific_year and count != 1 and percent_complete >= current_percent:222 logger.info(str(current_percent) + "%")223 current_percent += 10224 for over_key in totals:225 for key in totals[over_key]:226 if key == "TOT":227 continue228 229 logger.info("Getting league total data for " + over_key + " : " + key)230 current_percent = 10231 count = 0232 for year in years:233 if over_key == "Playoffs" and year == end_year and not current_year_playoffs_started:234 logger.info("Skipping current year " + str(year) + " as playoffs have not stared yet")235 continue236 request = urllib.request.Request(league_totals_url.format("playoffs" if over_key == "Playoffs" else "leagues", year + 1, format_strs[key]), headers=request_headers)237 try:238 response, player_page = url_request(request)239 except urllib.error.HTTPError as err:240 if err.status == 404:241 continue242 else:243 raise244 245 table = player_page.find("table", id="stats")246 if not table:247 continue248 if key == "Goalie":249 if not str(year) in totals[over_key][key]["G"]:250 totals[over_key][key]["G"][str(year)] = {}251 else:252 if not str(year) in totals[over_key][key]["F"]:253 totals[over_key][key]["F"][str(year)] = {}254 totals[over_key][key]["D"][str(year)] = {}255 header_columns = table.find("thead").find("tr", {"class" : "over_header"}).find_next_sibling().find_all("th")256 header_values = []257 for header in header_columns:258 header_values.append(header.find(text=True).strip())259 standard_table_rows = table.find("tbody").find_all("tr")260 for row in standard_table_rows:261 classes = row.get("class")262 if not classes or not "thead" in classes:263 team = row.find("td", {"data-stat" : "team_id"}).find(text=True)264 if key == "Goalie":265 pos = "G"266 else:267 pos = row.find("td", {"data-stat" : "pos"}).find(text=True)268 pos = "D" if pos == "D" else "F"269 if team == "TOT":270 continue271 columns = row.find_all("td", recursive=False)272 for sub_index, column in enumerate(columns):273 real_index = sub_index + 1274 header_value = header_values[real_index]275 if header_value == "TOI":276 continue277 elif header_value == "ATOI" or header_value == "MIN":278 header_value = "TOI"279 elif header_value == "PP":280 if column["data-stat"] == "goals_pp":281 header_value = "PPG"282 else:283 header_value = "PPA"284 elif header_value == "SH":285 if column["data-stat"] == "goals_sh":286 header_value = "SHG"287 if header_value in headers_to_read[key]:288 column_contents = column.find(text=True)289 column_value = 0.0290 if column_contents:291 if header_value == "TOI":292 if column_contents.isdigit():293 column_value = int(column_contents) * 60294 else:295 time_split = column_contents.split(":")296 minutes = int(time_split[0])297 seconds = int(time_split[1])298 column_value = (minutes * 60) + seconds299 column_value *= int(row.find("td", {"data-stat" : "games_played"}).find(text=True))300 else:301 column_value = float(column_contents)302 if not team in totals[over_key][key][pos][str(year)]:303 totals[over_key][key][pos][str(year)][team] = {}304 if not header_value in totals[over_key][key][pos][str(year)][team]:305 totals[over_key][key][pos][str(year)][team][header_value] = 0.0306 totals[over_key][key][pos][str(year)][team][header_value] += column_value307 308 if not str(year) in totals[over_key]["TOT"]:309 totals[over_key]["TOT"][str(year)] = {}310 if key == "Skater":311 for pos in ["F", "D"]:312 for team in totals[over_key][key][pos][str(year)]:313 if not team in totals[over_key]["TOT"][str(year)]:314 totals[over_key]["TOT"][str(year)][team] = {}315 for header_value in totals[over_key][key][pos][str(year)][team]:316 if not header_value in totals[over_key]["TOT"][str(year)][team]:317 totals[over_key]["TOT"][str(year)][team][header_value] = 0.0318 totals[over_key]["TOT"][str(year)][team][header_value] += totals[over_key][key][pos][str(year)][team][header_value]319 else:320 for team in totals[over_key][key]["G"][str(year)]:321 if not team in totals[over_key]["TOT"][str(year)]:322 totals[over_key]["TOT"][str(year)][team] = {}323 for header_value in totals[over_key][key]["G"][str(year)][team]:324 if not header_value in totals[over_key]["TOT"][str(year)][team]:325 totals[over_key]["TOT"][str(year)][team][header_value] = 0.0326 totals[over_key]["TOT"][str(year)][team][header_value] += totals[over_key][key]["G"][str(year)][team][header_value]327 328 count += 1329 percent_complete = 100 * (count / len(years))330 if not specific_year and count != 1 and percent_complete >= current_percent:331 logger.info(str(current_percent) + "%")332 current_percent += 10333 for over_key in totals:334 for key in totals[over_key]:335 logger.info("Combining league total data for " + over_key + " : " + key)336 if key == "TOT":337 for year in years:338 if str(year) in totals[over_key][key]:339 totals[over_key][key][str(year)]["NHL"] = {}340 for team in totals[over_key][key][str(year)]:341 if team != "NHL":342 for header_value in team_map_by_year[over_key][str(year)][team]:343 totals[over_key][key][str(year)][team][header_value] = team_map_by_year[over_key][str(year)][team][header_value]344 for header_value in totals[over_key][key][str(year)][team]:345 if header_value not in totals[over_key][key][str(year)]["NHL"]:346 totals[over_key][key][str(year)]["NHL"][header_value] = 0.0347 totals[over_key][key][str(year)]["NHL"][header_value] += totals[over_key][key][str(year)][team][header_value]348 for year_game_played in year_games_played:349 year_start_year = year_game_played["start_year"]350 year_end_year = year_game_played["end_year"]351 if (not year_start_year or year >= year_start_year) and (not year_end_year or year <= year_end_year):352 roster_per_season = year_game_played["roster"]353 354 totals[over_key][key][str(year)]["NHL"]["roster_size"] = roster_per_season355 else:356 for pos in totals[over_key][key]:357 for year in years:358 if str(year) in totals[over_key][key][pos]:359 totals[over_key][key][pos][str(year)]["NHL"] = {}360 for team in totals[over_key][key][pos][str(year)]:361 if team != "NHL":362 if key == "Skater":363 for header_value in team_map_by_year[over_key][str(year)][team]:364 totals[over_key][key][pos][str(year)][team][header_value] = team_map_by_year[over_key][str(year)][team][header_value]365 for header_value in totals[over_key][key][pos][str(year)][team]:366 if header_value not in totals[over_key][key][pos][str(year)]["NHL"]:367 totals[over_key][key][pos][str(year)]["NHL"][header_value] = 0.0368 totals[over_key][key][pos][str(year)]["NHL"][header_value] += totals[over_key][key][pos][str(year)][team][header_value]369 return totals370def calculate_year_games_by_team(year, for_playoffs):371 teams = {}372 request = urllib.request.Request(current_year_stats_url.format("playoffs" if for_playoffs else "leagues", year + 1), headers=request_headers)373 try:374 response, player_page = url_request(request)375 except urllib.error.HTTPError as err:376 if err.status == 404:377 return None378 else:379 raise380 table_name = "^teams$" if for_playoffs else "^stats"381 team_abbr_map = {}382 if for_playoffs:383 original_player_page = player_page384 request = urllib.request.Request(current_year_stats_url.format("leagues", year + 1), headers=request_headers)385 try:386 response, player_page = url_request(request)387 except urllib.error.HTTPError as err:388 if err.status == 404:389 return None390 else:391 raise392 table = player_page.find("table", id="stats")393 if not table:394 comments = player_page.find_all(string=lambda text: isinstance(text, Comment))395 for c in comments:396 temp_soup = BeautifulSoup(c, "lxml")397 temp_table = temp_soup.find("table", id="stats")398 if temp_table:399 table = temp_table400 break401 if table:402 standard_table_rows = table.find("tbody").find_all("tr")403 for row in standard_table_rows:404 classes = row.get("class")405 if not classes or not "thead" in classes:406 team_row = row.find("td", {"data-stat" : "team_name"})407 team_link = row.find("td", {"data-stat" : "team_name"}).find("a")408 if not team_link:409 continue410 team_name = team_row.find(text=True)411 team_abbr = team_link["href"].split("/")[2].upper()412 if not team_abbr in team_abbr_map:413 team_abbr_map[team_name] = team_abbr414 415 player_page = original_player_page416 tables = player_page.findAll("table", id=re.compile(table_name))417 if not tables:418 comments = player_page.find_all(string=lambda text: isinstance(text, Comment))419 for c in comments:420 temp_soup = BeautifulSoup(c, "lxml")421 temp_tables = temp_soup.findAll("table", id=re.compile(table_name))422 if temp_tables:423 tables = temp_tables424 break425 for table in tables:426 standard_table_rows = table.find("tbody").find_all("tr")427 header_columns = table.find("thead").find_all("th")428 429 header_values = []430 for header in header_columns:431 header_text = header.find(text=True)432 if header_text:433 header_values.append(header_text.strip())434 else:435 header_values.append(None)436 standard_table_rows = table.find("tbody").find_all("tr")437 for row in standard_table_rows:438 classes = row.get("class")439 if not classes or not "thead" in classes:440 if for_playoffs:441 team_name = row.find("td", {"data-stat" : "team_name"}).find(text=True)442 if team_name == "League Average":443 continue444 team_abbr = team_abbr_map[team_name]445 else:446 team_link = row.find("td", {"data-stat" : "team_name"}).find("a")447 if not team_link:448 continue449 team_abbr = team_link["href"].split("/")[2].upper()450 columns = row.find_all("td", recursive=False)451 for column in columns:452 if hasattr(column, "data-stat"):453 if column["data-stat"] == "games":454 header_value = "T-GP"455 elif column["data-stat"] == "goals":456 header_value = "T-GF"457 elif column["data-stat"] == "goals_against" or column["data-stat"] == "opp_goals":458 header_value = "T-GA"459 elif column["data-stat"] == "points":460 header_value = "T-PTS"461 else:462 continue463 column_contents = column.find(text=True)464 column_value = 0465 if column_contents:466 column_value = int(column_contents)467 468 if not team_abbr in teams:469 teams[team_abbr] = {}470 if not header_value in teams[team_abbr]:471 teams[team_abbr][header_value] = 0.0472 if header_value == "T-GF":473 wins_shootout = row.find("td", {"data-stat" : "wins_shootout"})474 if wins_shootout:475 wins_shootout_str = wins_shootout.find(text=True)476 if wins_shootout_str and wins_shootout_str.isdigit():477 column_value += int(wins_shootout_str)478 elif header_value == "T-GA":479 losses_shootout = row.find("td", {"data-stat" : "losses_shootout"})480 if losses_shootout:481 losses_shootout_str = losses_shootout.find(text=True)482 if losses_shootout_str and losses_shootout_str.isdigit():483 column_value += int(losses_shootout_str)484 485 teams[team_abbr][header_value] = column_value486 return teams487def url_request(request, timeout=30):488 failed_counter = 0489 while(True):490 try:491 response = urllib.request.urlopen(request, timeout=timeout)492 text = response.read()493 try:494 text = text.decode(response.headers.get_content_charset())495 except UnicodeDecodeError:496 return response, BeautifulSoup(text, "html.parser")497 return response, BeautifulSoup(text, "lxml")498 except Exception:499 failed_counter += 1500 if failed_counter > max_request_retries:501 raise502 delay_step = 10503 logger.info("#" + str(threading.get_ident()) + "# " + "Retrying in " + str(retry_failure_delay) + " seconds to allow request to " + request.get_full_url() + " to chill")504 time_to_wait = int(math.ceil(float(retry_failure_delay)/float(delay_step)))505 for i in range(retry_failure_delay, 0, -time_to_wait):506 logger.info("#" + str(threading.get_ident()) + "# " + str(i))507 time.sleep(time_to_wait)508 logger.info("#" + str(threading.get_ident()) + "# " + "0")509if __name__ == "__main__":...
derived.py
Source:derived.py
1# STD-lib2# 3rd-party3import numpy as np4# Local5from pyigra2.base import IGRABase6class Derived(IGRABase):7 def __init__(self, filename):8 # Init parent class9 super().__init__(filename)10 # Set file specific headers and parameters11 # OBS! These index values are exactly what was given in "igra2-derived-format.txt". However, python start index12 # with zero. This is taken care of in parent class IGRABase._set_header() and IGRABase._set_parameters.13 # Header name and index14 self._header_name_index = {15 "HEADREC": [1, 1],16 "ID": [2, 12],17 "YEAR": [14, 17],18 "MONTH": [19, 20],19 "DAY": [22, 23],20 "HOUR": [25, 26],21 "RELTIME": [28, 31],22 "NUMLEV": [32, 36],23 "PW": [38, 43],24 "INVPRESS": [44, 49],25 "INVHGT": [50, 55],26 "INVTEMPDIF": [56, 61],27 "MIXPRESS": [62, 67],28 "MIXHGT": [68, 73],29 "FRZPRESS": [74, 79],30 "FRZHGT": [80, 85],31 "LCLPRESS": [86, 91],32 "LCLHGT": [92, 97],33 "LFCPRESS": [98, 103],34 "LFCHGT": [104, 109],35 "LNBPRESS": [110, 115],36 "LNBHGT": [116, 121],37 "LI": [122, 127],38 "SI": [128, 133],39 "KI": [134, 139],40 "TTI": [140, 145],41 "CAPE": [146, 151],42 "CIN": [152, 157],43 }44 # Header units:45 # Structure: header_name: [raw_unit, converted_unit]46 self._header_units = {47 "HEADREC": ["-", "-"],48 "ID": ["-", "-"],49 "YEAR": ["yyyy", "yyyy"],50 "MONTH": ["mm", "mm"],51 "DAY": ["dd", "dd"],52 "HOUR": ["HH", "HH"],53 "RELTIME": ["HHMM", "HHMM"],54 "NUMLEV": ["-", "-"],55 "PW": ["mm*100", "mm"],56 "INVPRESS": ["Pa", "Pa"],57 "INVHGT": ["m", "m"],58 "INVTEMPDIF": ["K*10", "K"],59 "MIXPRESS": ["Pa", "Pa"],60 "MIXHGT": ["m", "m"],61 "FRZPRESS": ["Pa", "Pa"],62 "FRZHGT": ["m", "m"],63 "LCLPRESS": ["Pa", "Pa"],64 "LCLHGT": ["m", "m"],65 "LFCPRESS": ["Pa", "Pa"],66 "LFCHGT": ["m", "m"],67 "LNBPRESS": ["Pa", "Pa"],68 "LNBHGT": ["m", "m"],69 "LI": ["deg C", "K"],70 "SI": ["deg C", "K"],71 "KI": ["deg C", "K"],72 "TTI": ["deg C", "K"],73 "CAPE": ["J/kg", "J/kg"],74 "CIN": ["J/kg", "J/kg"],75 }76 # Parameter name and index77 self._parameters_name_index = {78 "PRESS": [1, 7],79 "REPGPH": [9, 15],80 "CALCGPH": [17, 23],81 "TEMP": [25, 31],82 "TEMPGRAD": [33, 39],83 "PTEMP": [41, 47],84 "PTEMPGRAD": [49, 55],85 "VTEMP": [57, 63],86 "VPTEMP": [65, 71],87 "VAPPRESS": [73, 79],88 "SATVAP": [81, 87],89 "REPRH": [89, 95],90 "CALCRH": [97, 103],91 "RHGRAD": [105, 111],92 "UWND": [113, 119],93 "UWDGRAD": [121, 127],94 "VWND": [129, 135],95 "VWNDGRAD": [137, 143],96 "N": [145, 151],97 }98 # Parameter units:99 # Structure: parameter_name: [raw unit, converted unit]100 self._parameter_units = {101 "PRESS": ["Pa", "Pa"],102 "REPGPH": ["m", "m"],103 "CALCGPH": ["m", "m"],104 "TEMP": ["K * 10", "K"],105 "TEMPGRAD": ["(K/km) * 10", "K/m"],106 "PTEMP": ["K * 10", "K"],107 "PTEMPGRAD": ["(K/km) * 10", "K/m"],108 "VTEMP": ["K * 10", "K"],109 "VPTEMP": ["K * 10", "K"],110 "VAPPRESS": ["mb * 1000", "Pa"],111 "SATVAP": ["mb * 1000", "Pa"],112 "REPRH": ["% * 10", "%"],113 "CALCRH": ["% * 10", "%"],114 "RHGRAD": ["(%/km) * 10", "%/m"],115 "UWND": ["(m/s) * 10", "m/s"],116 "UWDGRAD": ["(m/s per km) * 10", "(m/s) / m"],117 "VWND": ["(m/s) * 10", "m/s"],118 "VWNDGRAD": ["(m/s per km) * 10", "(m/s) / m"],119 "N": ["-", "-"],120 }121 def _convert_header(self, header, date, hour):122 """Convert header123 :param header: header to convert124 :param date, date to update125 :param hour: hour to update126 :return: None127 """128 # Create target dict129 self.converted_data[date][hour]["header"] = {}130 # Remove whitespaces:131 for header_name, header_value in header.items():132 # Remove white space133 header_value = header_value.replace(" ", "")134 # These variables have the following definitions:135 # HEADREC is the header record indicator (always set to "#").136 # ID is the station identification code. See "igra2-stations.txt"137 # for a complete list of stations and their names and locations.138 # YEAR is the year of the sounding.139 # MONTH is the month of the sounding.140 # DAY is the day of the sounding.141 # HOUR is the hour of the sounding (99 = missing).142 # RELTIME is the release time of the sounding (format HHMM, missing=9999).143 # NUMLEV is the number of levels in the sounding (i.e., the number of144 # data records that follow).145 if header_name == "NUMLEV":146 header_value = IGRABase._missing_test("-99999", header_value)147 # New unit: -148 # PW is the precipitable water (mm*100) between the surface and 500 hPa.149 if header_name == "PW":150 header_value = IGRABase._missing_test("-99999", header_value)151 header_value = header_value / 100.0152 # New unit: mm153 # INVPRESS is the pressure (in Pa or mb*100) at the level of the154 # warmest temperature in the sounding. Only provided if155 # the warmest temperature is above the surface.156 if header_name == "INVPRESS":157 header_value = IGRABase._missing_test("-99999", header_value)158 # New unit: Pa159 # INVHGT is the height (in meters above the surface) of the warmest160 # temperature in the sounding. Only provided when the161 # warmest temperature is above the surface.162 if header_name == "INVHGT":163 header_value = IGRABase._missing_test("-99999", header_value)164 # New unit: m165 # INVTEMPDIF is the difference between the warmest temperature in the166 # sounding and the surface temperature (K * 10). Only provided if167 # the warmest temperature is above the surface.168 if header_name == "INVTEMPDIF":169 header_value = IGRABase._missing_test("-99999", header_value)170 header_value = header_value / 10.0171 # New unit: K172 # MIXPRESS is the pressure (in Pa or mb * 100) at the top of the173 # mixed layer as determined using the parcel method.174 if header_name == "MIXPRESS":175 header_value = IGRABase._missing_test("-99999", header_value)176 # New unit: Pa177 # MIXHGT is the height (in meters above the surface) of the top of the178 # mixed layer As determined using the parcel method.179 if header_name == "MIXHGT":180 header_value = IGRABase._missing_test("-99999", header_value)181 # New unit: m182 # FRZPRESS is the pressure (in Pa or mb * 100) where the temperature183 # first reaches the freezing point when moving upward from184 # the surface. Determined by interpolating linearly with respect185 # to the logarithm of pressure between adjacent reported levels.186 # Not provided if the surface temperature is below freezing.187 if header_name == "FRZPRESS":188 header_value = IGRABase._missing_test("-99999", header_value)189 # New unit: Pa190 # FRZHGT is the height (in meters above the surface) where the temperature191 # first reaches the freezing point when moving upward from the192 # surface. Determined analogously to FRZPRESS. Not provided if the193 # surface temperature is below freezing.194 if header_name == "FRZHGT":195 header_value = IGRABase._missing_test("-99999", header_value)196 # New unit: m197 # LCLPRESS is the pressure (in Pa or mb * 100) of the lifting condensation198 # level.199 if header_name == "LCLPRESS":200 header_value = IGRABase._missing_test("-99999", header_value)201 # New unit: Pa202 # LCLHGT is the height (in meters above the surface) of the lifting203 # condensation level.204 if header_name == "LCLHGT":205 header_value = IGRABase._missing_test("-99999", header_value)206 # New unit: m207 # LFCPRESS is the pressure (in Pa or mb * 100) of the level of free convection.208 if header_name == "LFCPRESS":209 header_value = IGRABase._missing_test("-99999", header_value)210 # New unit: Pa211 # LFCHGT is the height (in meters above the surface) of the level of free212 # convection.213 if header_name == "LFCHGT":214 header_value = IGRABase._missing_test("-99999", header_value)215 # New unit: m216 # LNBPRESS is the pressure (in Pa or mb * 100) of the level of217 # neutral buoyancy (or equilibrium level).218 if header_name == "LNBPRESS":219 header_value = IGRABase._missing_test("-99999", header_value)220 # New unit: Pa221 # LNBHGT is the height (in meters above the surface) of the level of222 # neutral buoyancy (or equilibrium level).223 if header_name == "LNBHGT":224 header_value = IGRABase._missing_test("-99999", header_value)225 # New unit: m226 # LI is the lifted index (in degrees C).227 if header_name == "LI":228 header_value = IGRABase._missing_test("-99999", header_value)229 header_value = header_value + 273.15230 # New unit: K231 # SI is the Showalter index (in degrees C).232 if header_name == "SI":233 header_value = IGRABase._missing_test("-99999", header_value)234 header_value = header_value + 273.15235 # New unit: K236 # KI is the K index (in degrees C).237 if header_name == "KI":238 header_value = IGRABase._missing_test("-99999", header_value)239 header_value = header_value + 273.15240 # New unit: K241 # TTI is the total totals index (in degrees C).242 if header_name == "TTI":243 header_value = IGRABase._missing_test("-99999", header_value)244 header_value = header_value + 273.15245 # New unit: K246 # CAPE is the convective available potential energy (in J/kg).247 if header_name == "CAPE":248 header_value = IGRABase._missing_test("-99999", header_value)249 # New unit: J/kg250 # CIN is the convective inhibition (in J/kg).251 if header_name == "CIN":252 header_value = IGRABase._missing_test("-99999", header_value)253 # New unit: J/kg254 # Add to new header255 self.converted_data[date][hour]["header"][header_name] = header_value256 def _convert_parameters(self, parameters, date, hour):257 """Convert data258 :param parameters: parameters to convert259 :param date, date to update260 :param hour: hour to update261 :return: None262 """263 # Create target dict264 self.converted_data[date][hour]["parameters"] = {}265 for param_name, value_lst in parameters.items():266 # For every parameter do:267 # Convert to numpy array with dtype str268 array = np.array(value_lst, dtype=np.str)269 # Remove white spaces270 array = np.char.replace(array, " ", "")271 # Convert to float due to nans272 array = array.astype(np.float)273 # Missing values: -99999274 array[array == -99999] = np.nan275 # Convert specific parameters:276 # PRESS is the reported pressure (Pa or mb * 100).277 # REPGPH is the reported geopotential height (meters). This value is278 # often not available at significant levels.279 # CALCGPH is the calculated geopotential height (meters). The geopotential280 # height has been estimated by applying the hydrostatic balance to281 # the atmospheric layer between the next lower level with a282 # reported geopotential height and the current level.283 # TEMP is the reported temperature (K * 10).284 if param_name == "TEMP":285 array = array / 10.0286 # New unit: K287 # TEMPGRAD is the temperature gradient between the current level and288 # the next higher level with a temperature [(K/km) * 10, positive289 # if temperature increases with height].290 if param_name == "TEMPGRAD":291 array = array / 10000.0292 # New unit: K/m293 # PTEMP is the potential temperature (K * 10).294 if param_name == "PTEMP":295 array = array / 10.0296 # New unit: K297 # PTEMPGRAD is the potential temperature gradient between the current level298 # and the next higher level with a potential temperature299 # [(K/km) * 10, positive if potential temperature increases300 # with height].301 if param_name == "PTEMPGRAD":302 array = array / 10000.0303 # New unit: K/m304 # VTEMP is the virtual temperature (K * 10).305 if param_name == "VTEMP":306 array = array / 10.0307 # New unit: K308 # VPTEMP is the virtual potential temperature (K * 10).309 if param_name == "VPTEMP":310 array = array / 10.0311 # New unit: K312 # VAPPRESS is the vapor pressure (mb * 1000) as computed from temperature,313 # pressure, and dewpoint depression at the same level.314 if param_name == "VAPPRESS":315 array = array / 10.0316 # New unit: Pa317 # SATVAP is the saturation vapor pressure (mb * 1000) as computed from318 # pressure and temperature at the same level.319 if param_name == "SATVAP":320 array = array / 10.0321 # New unit: Pa322 # REPRH is the relative humidity (Percent * 10) as reported in the323 # original sounding.324 if param_name == "REPRH":325 array = array / 10.0326 # New unit: %327 # CALCRH is the relative humidity (Percent * 10) as calculated from vapor328 # pressure, saturation vapor pressure, and pressure at the same329 # level.330 if param_name == "CALCRH":331 array = array / 10.0332 # New unit: %333 # RHGRAD is the relative humidity gradient between the current level and334 # the next higher usable level [(%/km) * 10, positive if relative335 # humidity increases with height].336 if param_name == "RHGRAD":337 array = array / 10000.0338 # New unit: %/m339 # UWND is the zonal wind component [(m/s) * 10] as computed from the340 # reported wind speed and direction.341 if param_name == "UWND":342 array = array / 10.0343 # New unit: m/s344 # UWDGRAD is the vertical gradient of the zonal wind between the current345 # level and the next higher level with a wind observation346 # [(m/s per km) * 10, positive if zonal wind becomes more347 # positive with height].348 if param_name == "UWDGRAD":349 array = array / 10000.0350 # New unit: (m/s) / m351 # VWND is the meridional wind component [(m/s) * 10] as computed352 # from the reported wind speed and direction.353 if param_name == "VWND":354 array = array / 10.0355 # New unit: m/s356 # VWNDGRAD is the vertical gradient of the meridional wind component357 # between the current level and the next higher level with a wind358 # observation [(m/s per km) * 10, positive if the meridional359 # wind becomes more positive with height].360 if param_name == "VWNDGRAD":361 array = array / 10000.0362 # New unit: (m/s) / m363 # N is the refractive index (unitless).364 # Add data to converted data...
header_building_and_parsing.py
Source:header_building_and_parsing.py
1__all__ = ()2import re3from .quoting import quote4_TOKEN_RP = re.compile(r'[-!#$%&\'*+.^_`|~0-9a-zA-Z]+')5_LIST_START_RP = re.compile('[\t ,]*')6_SPACE_RP = re.compile('[\t ]*')7_PROTOCOL_RP = re.compile(r'[-!#$%&\'*+.^_`|~0-9a-zA-Z]+(?:/[-!#$%&\'*+.^_`|~0-9a-zA-Z]+)?')8CHARS = frozenset((chr(i) for i in range(0, 128)))9CONTROLS = frozenset((*(chr(i) for i in range(0, 32)), chr(127)))10SEPARATORS = frozenset(('(', ')', '<', '>', '@', ', ', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ',11 chr(9)))12TOKENS = CHARS ^ CONTROLS ^ SEPARATORS13def build_extensions(available_extensions):14 """15 Builds websocket extensions header from the given extension values.16 17 Parameters18 ----------19 available_extensions : `list` of `Any`20 Each websocket extension should have the following `4` attributes / methods:21 - `name`: `str`. The extension's name.22 - `request_params` : `list` of `tuple` (`str`, `str`). Additional header parameters of the extension.23 - `decode` : `callable`. Decoder method, what processes a received websocket frame. Should accept `2`24 parameters: The respective websocket ``Frame``, and the Ëmax_size` as `int`, what decides the25 maximal size of a received frame. If it is passed, ``PayloadError`` is raised.26 - `encode` : `callable`. Encoder method, what processes the websocket frames to send. Should accept `1`27 parameter, the respective websocket ``Frame``.28 29 Returns30 -------31 header_value : `str`32 """33 main_parts = []34 sub_parts = []35 36 for available_extension in available_extensions:37 name = available_extension.name38 parameters = available_extension.request_params39 40 sub_parts.append(name)41 for key, value in parameters:42 if value is None:43 sub_parts.append(key)44 else:45 sub_parts.append(f'{key}={value}')46 47 main_parts.append('; '.join(sub_parts))48 sub_parts.clear()49 50 return ', '.join(main_parts)51def parse_extensions(header_value):52 """53 Parses extension header.54 55 Parameters56 ----------57 header_value : `str`58 Received extension header.59 Returns60 -------61 result : `list` of `tuple` (`str`, `list` of `tuple` (`str`, `str`))62 The parsed out extensions as `name` - `parameters` pairs. The `parameters` are in `list` storing63 `key` - `value` pairs.64 65 Raises66 ------67 ValueError68 Extension header value is incorrect.69 """70 result = []71 limit = len(header_value)72 index = 073 74 check_start = True75 76 while True:77 # parse till 1st element78 matched = _LIST_START_RP.match(header_value, index)79 index = matched.end()80 81 # are we at the end?82 if index == limit:83 return result84 85 # now lets parse the extension's name86 matched = _TOKEN_RP.match(header_value, index)87 if matched is None:88 raise ValueError(89 f'Expected extension name since index {index!r}, got {header_value!r}.'90 )91 92 name = matched.group(0)93 index = matched.end()94 95 # nice, we have a name, we can make our item now!96 sub_parts = []97 result.append((name, sub_parts,),)98 99 # should we parse a sublist?100 while True:101 102 # after half item we skip this part103 if check_start:104 # are we at the end?105 if index == limit:106 return result107 108 # lets parse till next character109 matched = _SPACE_RP.match(header_value, index)110 index = matched.end()111 112 # are we at the end?113 if index == limit:114 return result115 116 # no sublist?117 if header_value[index] == ',':118 index += 1119 break120 # invalid character121 if header_value[index] != ';':122 raise ValueError(123 f'Expected \';\' at index {index!r}, got {header_value!r}.'124 )125 126 # we have a sublist127 index += 1128 129 else:130 check_start = True131 132 # parse space133 matched = _SPACE_RP.match(header_value, index)134 index = matched.end()135 136 # are we at the end?137 if index == limit:138 break139 140 # lets parse the key now141 matched = _TOKEN_RP.match(header_value, index)142 if matched is None:143 raise ValueError(144 f'Expected parameter name since index {index!r}, got {header_value!r}.'145 )146 147 key = matched.group(0)148 index = matched.end()149 150 # are we at the end?151 if index == limit:152 sub_parts.append((key, None,),)153 break154 155 # parse space156 matched = _SPACE_RP.match(header_value, index)157 index = matched.end()158 159 # are we at the end?160 if index == limit:161 sub_parts.append((key, None,),)162 break163 #is it a full item or a half?164 165 #next extension166 if header_value[index] == ',':167 sub_parts.append((key, None,),)168 index += 1169 break170 # next item171 if header_value[index] == ';':172 sub_parts.append((key, None,),)173 index += 1174 check_start = False175 continue176 #invalid character177 if header_value[index] != '=':178 raise ValueError(179 f'Expected \',\' or \';\' or \'=\' at index {index!r}, got {header_value!r}.'180 )181 182 index += 1183 184 # parse space185 matched = _SPACE_RP.match(header_value, index)186 index = matched.end()187 188 # are we at the end?189 if index == limit:190 raise ValueError(191 f'Expected a parameter value, but string ended, got {header_value!r}.'192 )193 194 # is it '"stuff"' ?195 if header_value[index] == '"':196 index += 1197 198 # are we at the end?199 if index == limit:200 raise ValueError(201 f'Expected a parameter value, but string ended, got {header_value!r}.'202 )203 204 matched = _TOKEN_RP.match(header_value, index)205 if matched is None:206 raise ValueError(207 f'Expected parameter value since index {index!r}, got {header_value!r}'208 )209 210 value = matched.group(0)211 index = matched.end()212 213 # are we at the end? or did we finish the string normally?214 if index == limit or header_value[index] != '"':215 raise ValueError(216 f'Expected a \'"\' after starting a value with \'"\', got {header_value!r}.'217 )218 index += 1219 220 # is it 'stuff' ?221 else:222 matched = _TOKEN_RP.match(header_value, index)223 if matched is None:224 raise ValueError(225 f'Expected parameter value since index {index!r}, got {header_value!r}.'226 )227 value = matched.group(0)228 index = matched.end()229 230 # we got a full item231 sub_parts.append((key, value,),)232def parse_connections(header_value):233 """234 Parses subprotocol or connection headers.235 236 Parameters237 ----------238 header_value : `str`239 Received subprotocol or connection header.240 241 Returns242 -------243 result : `list` of `str`244 The parsed subprotocol or connection headers.245 246 Raises247 ------248 ValueError249 Subprotocol or connection header value is incorrect.250 """251 result = []252 limit = len(header_value)253 index = 0254 255 while True:256 #parse till 1st element257 matched = _LIST_START_RP.match(header_value, index)258 index = matched.end()259 260 #are we at the end?261 if index == limit:262 return result263 264 #now lets parse the upgrade's name265 matched = _TOKEN_RP.match(header_value, index)266 if matched is None:267 raise ValueError(268 f'Expected upgrade type since index {index!r}, got {header_value!r}.'269 )270 271 name = matched.group(0)272 index = matched.end()273 #nice274 result.append(name)275 276 #are we at the end?277 if index == limit:278 return result279 #lets parse till next character280 matched = _SPACE_RP.match(header_value, index)281 index = matched.end()282 #are we at the end?283 if index == limit:284 return result285 286 #no sublist?287 if header_value[index] == ',':288 index += 1289 continue290 291 raise ValueError(292 f'Expected \',\' at index {index!r}, got {header_value!r}.'293 )294def build_subprotocols(subprotocols):295 """296 Builds websocket subprotocol headers from the given subprotocol values.297 298 Parameters299 ----------300 subprotocols : `list` of `str`301 A list of supported subprotocols.302 303 Returns304 -------305 header_value : `str`306 """307 return ', '.join(subprotocols)308parse_subprotocols = parse_connections # yes, these are the same309def parse_upgrades(header_value):310 """311 Parses upgrade headers.312 313 Parameters314 ----------315 header_value : `str`316 Received upgrade header.317 318 Returns319 -------320 result : `list` of `str`321 The parsed upgrade headers.322 323 Raises324 ------325 ValueError326 Upgrade header value is incorrect.327 """328 result = []329 limit = len(header_value)330 index = 0331 332 while True:333 # parse till 1st element334 matched = _LIST_START_RP.match(header_value, index)335 index = matched.end()336 337 # are we at the end?338 if index == limit:339 return result340 341 # now lets parse the upgrade's name342 matched = _PROTOCOL_RP.match(header_value, index)343 if matched is None:344 raise ValueError(345 f'Expected upgrade type since index {index!r}, got {header_value!r}.'346 )347 name = matched.group(0)348 index = matched.end()349 350 # nice351 result.append(name)352 353 # are we at the end?354 if index == limit:355 return result356 357 # lets parse till next character358 matched = _SPACE_RP.match(header_value, index)359 index = matched.end()360 361 # are we at the end?362 if index == limit:363 return result364 365 # no sublist?366 if header_value[index] == ',':367 index += 1368 continue369 370 raise ValueError(371 f'Expected \',\' at index {index!r}, got {header_value!r}.'372 )373def build_content_disposition_header(disposition_type, parameters, quote_fields):374 """375 Creates Content-Disposition header value.376 377 Parameters378 ----------379 disposition_type : `str`380 Disposition type. Can be one of following: `'inline'`, `'attachment'`, '`form-data`'.381 parameters : `dict` of (`str`, `str`) items382 Disposition parameters.383 quote_fields : `bool`384 Whether field values should be quoted.385 386 Returns387 -------388 value : `str`389 """390 if (not disposition_type) or not (TOKENS > set(disposition_type)):391 raise ValueError(392 f'Bad content disposition type {disposition_type!r}.'393 )394 395 if parameters:396 parameter_parts = [disposition_type]397 for key, value in parameters.items():398 if (not key) or (not (TOKENS > set(key))):399 raise ValueError(400 f'Bad content disposition parameter {key!r}={value!r}.'401 )402 403 if quote_fields:404 value = quote(value, '[]')405 406 parameter_parts.append('; ')407 408 parameter_parts.append(key)409 parameter_parts.append('="')410 parameter_parts.append(value)411 parameter_parts.append('"')412 413 if key == 'filename':414 parameter_parts.append('; filename*=utf-8\'\'')415 parameter_parts.append(value)416 417 value = ''.join(parameter_parts)418 else:419 value = disposition_type420 ...
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!