Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/yarl/_query.py: 23%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

57 statements  

1"""Query string handling.""" 

2 

3import math 

4from collections.abc import Iterable, Mapping, Sequence 

5from typing import Any, SupportsInt, Union 

6 

7from multidict import istr 

8 

9from ._quoters import QUERY_PART_QUOTER, QUERY_QUOTER 

10 

11SimpleQuery = Union[str, SupportsInt, float] 

12QueryVariable = Union[SimpleQuery, Sequence[SimpleQuery]] 

13Query = Union[ 

14 None, str, Mapping[str, QueryVariable], Sequence[tuple[str, QueryVariable]] 

15] 

16 

17 

18def query_var(v: SimpleQuery) -> str: 

19 """Convert a query variable to a string.""" 

20 cls = type(v) 

21 if cls is int: # Fast path for non-subclassed int 

22 return str(v) 

23 if isinstance(v, str): 

24 return v 

25 if isinstance(v, float): 

26 if math.isinf(v): 

27 raise ValueError("float('inf') is not supported") 

28 if math.isnan(v): 

29 raise ValueError("float('nan') is not supported") 

30 return str(float(v)) 

31 if cls is not bool and isinstance(v, SupportsInt): 

32 return str(int(v)) 

33 raise TypeError( 

34 "Invalid variable type: value " 

35 "should be str, int or float, got {!r} " 

36 "of type {}".format(v, cls) 

37 ) 

38 

39 

40def get_str_query_from_sequence_iterable( 

41 items: Iterable[tuple[Union[str, istr], QueryVariable]], 

42) -> str: 

43 """Return a query string from a sequence of (key, value) pairs. 

44 

45 value is a single value or a sequence of values for the key 

46 

47 The sequence of values must be a list or tuple. 

48 """ 

49 quoter = QUERY_PART_QUOTER 

50 pairs = [ 

51 f"{quoter(k)}={quoter(v if type(v) is str else query_var(v))}" 

52 for k, val in items 

53 for v in ( 

54 val if type(val) is not str and isinstance(val, (list, tuple)) else (val,) 

55 ) 

56 ] 

57 return "&".join(pairs) 

58 

59 

60def get_str_query_from_iterable( 

61 items: Iterable[tuple[Union[str, istr], SimpleQuery]], 

62) -> str: 

63 """Return a query string from an iterable. 

64 

65 The iterable must contain (key, value) pairs. 

66 

67 The values are not allowed to be sequences, only single values are 

68 allowed. For sequences, use `_get_str_query_from_sequence_iterable`. 

69 """ 

70 quoter = QUERY_PART_QUOTER 

71 # A listcomp is used since listcomps are inlined on CPython 3.12+ and 

72 # they are a bit faster than a generator expression. 

73 pairs = [ 

74 f"{quoter(k)}={quoter(v if type(v) is str else query_var(v))}" for k, v in items 

75 ] 

76 return "&".join(pairs) 

77 

78 

79def get_str_query(*args: Any, **kwargs: Any) -> Union[str, None]: 

80 """Return a query string from supported args.""" 

81 query: Union[str, Mapping[str, QueryVariable], None] 

82 if kwargs: 

83 if args: 

84 msg = "Either kwargs or single query parameter must be present" 

85 raise ValueError(msg) 

86 query = kwargs 

87 elif len(args) == 1: 

88 query = args[0] 

89 else: 

90 raise ValueError("Either kwargs or single query parameter must be present") 

91 

92 if query is None: 

93 return None 

94 if not query: 

95 return "" 

96 if type(query) is dict: 

97 return get_str_query_from_sequence_iterable(query.items()) 

98 if type(query) is str or isinstance(query, str): 

99 return QUERY_QUOTER(query) 

100 if isinstance(query, Mapping): 

101 return get_str_query_from_sequence_iterable(query.items()) 

102 if isinstance(query, (bytes, bytearray, memoryview)): # type: ignore[unreachable] 

103 msg = "Invalid query type: bytes, bytearray and memoryview are forbidden" 

104 raise TypeError(msg) 

105 if isinstance(query, Sequence): 

106 # We don't expect sequence values if we're given a list of pairs 

107 # already; only mappings like builtin `dict` which can't have the 

108 # same key pointing to multiple values are allowed to use 

109 # `_query_seq_pairs`. 

110 return get_str_query_from_iterable(query) 

111 raise TypeError( 

112 "Invalid query type: only str, mapping or " 

113 "sequence of (key, value) pairs is allowed" 

114 )