0
# Query Parameter Handling
1
2
Comprehensive query string manipulation with support for multiple values per parameter, various input formats, and MultiDict integration for robust parameter handling.
3
4
## Type Definitions
5
6
YARL provides flexible type definitions for query parameters to support various input formats.
7
8
```python { .api }
9
from typing import Union, Sequence, Mapping, SupportsInt
10
11
SimpleQuery = Union[str, SupportsInt, float]
12
"""Simple query value types: string, integer-like, or float"""
13
14
QueryVariable = Union[SimpleQuery, Sequence[SimpleQuery]]
15
"""Query variable: single value or sequence of values for multi-value parameters"""
16
17
Query = Union[
18
None,
19
str,
20
Mapping[str, QueryVariable],
21
Sequence[tuple[str, QueryVariable]]
22
]
23
"""Query parameter input types: None, string, mapping, or sequence of tuples"""
24
```
25
26
## Capabilities
27
28
### Query Parameter Modification
29
30
Methods for modifying query parameters in URLs, supporting various input formats and merge strategies.
31
32
```python { .api }
33
def with_query(self, query: Query = None, **kwargs: QueryVariable) -> "URL":
34
"""
35
Return URL with completely replaced query parameters.
36
37
Args:
38
query (Query, optional): New query parameters
39
**kwargs: Query parameters as keyword arguments
40
41
Returns:
42
URL: New URL with replaced query parameters
43
44
Examples:
45
url.with_query({'key': 'value'})
46
url.with_query([('key', 'value1'), ('key', 'value2')])
47
url.with_query('key=value&other=data')
48
url.with_query(key='value', other='data')
49
"""
50
51
def extend_query(self, query: Query = None, **kwargs: QueryVariable) -> "URL":
52
"""
53
Return URL with additional query parameters appended to existing ones.
54
55
Args:
56
query (Query, optional): Additional query parameters
57
**kwargs: Additional query parameters as keyword arguments
58
59
Returns:
60
URL: New URL with extended query parameters
61
62
Examples:
63
# Add to existing parameters
64
url.extend_query({'new_key': 'value'})
65
url.extend_query(new_key='value')
66
"""
67
68
def update_query(self, query: Query = None, **kwargs: QueryVariable) -> "URL":
69
"""
70
Return URL with updated query parameters (merge strategy).
71
72
Existing parameters are preserved unless explicitly overridden.
73
74
Args:
75
query (Query, optional): Query parameters to update/add
76
**kwargs: Query parameters as keyword arguments
77
78
Returns:
79
URL: New URL with updated query parameters
80
81
Examples:
82
# Update existing 'limit', add new 'sort'
83
url.update_query({'limit': 100, 'sort': 'name'})
84
"""
85
86
def without_query_params(self, *query_params: str) -> "URL":
87
"""
88
Return URL without specified query parameters.
89
90
Args:
91
*query_params (str): Names of parameters to remove
92
93
Returns:
94
URL: New URL with specified parameters removed
95
96
Examples:
97
url.without_query_params('limit', 'offset')
98
"""
99
```
100
101
### Query Processing Functions
102
103
Low-level functions for processing query parameters into string format.
104
105
```python { .api }
106
def query_var(v: SimpleQuery) -> str:
107
"""
108
Convert a query variable to its string representation.
109
110
Args:
111
v (SimpleQuery): Value to convert (str, int, float, or SupportsInt)
112
113
Returns:
114
str: String representation of the value
115
116
Raises:
117
ValueError: For float('inf') or float('nan')
118
TypeError: For unsupported types
119
"""
120
121
def get_str_query(*args, **kwargs) -> str | None:
122
"""
123
Convert various query input formats to query string.
124
125
Args:
126
*args: Single query argument (Query type)
127
**kwargs: Query parameters as keyword arguments
128
129
Returns:
130
str | None: Query string or None if no parameters
131
132
Raises:
133
ValueError: If both args and kwargs provided
134
"""
135
136
def get_str_query_from_sequence_iterable(
137
items: Iterable[tuple[Union[str, istr], QueryVariable]]
138
) -> str:
139
"""
140
Convert sequence of (key, value) pairs to query string.
141
142
Supports multi-value parameters where value can be a sequence.
143
144
Args:
145
items: Iterable of (key, value) pairs
146
147
Returns:
148
str: URL-encoded query string
149
"""
150
151
def get_str_query_from_iterable(
152
items: Iterable[tuple[Union[str, istr], SimpleQuery]]
153
) -> str:
154
"""
155
Convert iterable of (key, value) pairs to query string.
156
157
Values must be simple (not sequences).
158
159
Args:
160
items: Iterable of (key, value) pairs
161
162
Returns:
163
str: URL-encoded query string
164
"""
165
```
166
167
### Query Access Properties
168
169
Access query parameters from URL objects.
170
171
```python { .api }
172
@property
173
def query(self) -> MultiDictProxy[str]:
174
"""
175
Query parameters as MultiDictProxy.
176
177
Provides dict-like access with support for multiple values per key.
178
179
Returns:
180
MultiDictProxy[str]: Read-only multi-value dictionary of parameters
181
"""
182
183
@property
184
def raw_query_string(self) -> str:
185
"""Raw (encoded) query string without leading '?'"""
186
187
@property
188
def query_string(self) -> str:
189
"""Decoded query string without leading '?'"""
190
191
@property
192
def path_qs(self) -> str:
193
"""Decoded path + query string combination"""
194
195
@property
196
def raw_path_qs(self) -> str:
197
"""Raw path + query string combination"""
198
```
199
200
## Usage Examples
201
202
### Basic Query Parameter Operations
203
204
```python
205
from yarl import URL
206
207
base_url = URL('https://api.example.com/users')
208
209
# Add query parameters
210
search_url = base_url.with_query({'q': 'john', 'active': True, 'limit': 10})
211
print(search_url) # https://api.example.com/users?q=john&active=True&limit=10
212
213
# Using keyword arguments
214
same_url = base_url.with_query(q='john', active=True, limit=10)
215
print(same_url) # https://api.example.com/users?q=john&active=True&limit=10
216
```
217
218
### Multi-Value Parameters
219
220
```python
221
from yarl import URL
222
223
url = URL('https://api.example.com/search')
224
225
# Multiple values for same parameter using list
226
multi_url = url.with_query({'tags': ['python', 'web', 'api'], 'active': True})
227
print(multi_url) # https://api.example.com/search?tags=python&tags=web&tags=api&active=True
228
229
# Using sequence of tuples for precise control
230
tuple_url = url.with_query([
231
('tags', 'python'),
232
('tags', 'web'),
233
('sort', 'date'),
234
('order', 'desc')
235
])
236
print(tuple_url) # https://api.example.com/search?tags=python&tags=web&sort=date&order=desc
237
```
238
239
### Query Parameter Types
240
241
```python
242
from yarl import URL
243
244
url = URL('https://api.example.com/data')
245
246
# Different parameter types
247
typed_url = url.with_query({
248
'string_param': 'text value',
249
'int_param': 42,
250
'float_param': 3.14,
251
'bool_param': True,
252
'list_param': [1, 2, 3]
253
})
254
print(typed_url)
255
# https://api.example.com/data?string_param=text+value&int_param=42&float_param=3.14&bool_param=True&list_param=1&list_param=2&list_param=3
256
257
# Note: boolean True becomes 'True', False becomes 'False'
258
```
259
260
### Extending and Updating Queries
261
262
```python
263
from yarl import URL
264
265
# Start with existing parameters
266
base_url = URL('https://api.example.com/users?active=true&limit=10')
267
268
# Extend with additional parameters
269
extended = base_url.extend_query({'sort': 'name', 'order': 'asc'})
270
print(extended) # https://api.example.com/users?active=true&limit=10&sort=name&order=asc
271
272
# Update existing parameters
273
updated = base_url.update_query({'limit': 50, 'offset': 20})
274
print(updated) # https://api.example.com/users?active=true&limit=50&offset=20
275
276
# Remove specific parameters
277
cleaned = extended.without_query_params('sort', 'order')
278
print(cleaned) # https://api.example.com/users?active=true&limit=10
279
```
280
281
### Working with Query Strings
282
283
```python
284
from yarl import URL
285
286
# From query string
287
url = URL('https://example.com/').with_query('name=john&age=30&tags=dev&tags=python')
288
print(url.query) # MultiDictProxy with parsed parameters
289
290
# Access individual parameters
291
print(url.query['name']) # 'john'
292
print(url.query.getlist('tags')) # ['dev', 'python']
293
294
# Get all parameter names and values
295
for key in url.query:
296
values = url.query.getlist(key)
297
print(f"{key}: {values}")
298
```
299
300
### Query Parameter Validation and Error Handling
301
302
```python
303
from yarl import URL
304
305
url = URL('https://api.example.com/')
306
307
# Valid numeric types
308
valid_url = url.with_query({
309
'page': 1,
310
'size': 50,
311
'ratio': 1.5
312
})
313
314
# Invalid types raise errors
315
try:
316
invalid_url = url.with_query({'infinity': float('inf')})
317
except ValueError as e:
318
print(f"Error: {e}") # float('inf') is not supported
319
320
try:
321
invalid_url = url.with_query({'nan': float('nan')})
322
except ValueError as e:
323
print(f"Error: {e}") # float('nan') is not supported
324
```
325
326
### Advanced Query Manipulation
327
328
```python
329
from yarl import URL
330
331
# Complex query building
332
api_url = URL('https://api.example.com/search')
333
334
# Build complex search query
335
search_params = {
336
'q': 'python web framework',
337
'categories': ['tutorials', 'documentation'],
338
'difficulty': ['beginner', 'intermediate'],
339
'published_after': '2023-01-01',
340
'sort': 'relevance',
341
'page': 1,
342
'per_page': 20
343
}
344
345
search_url = api_url.with_query(search_params)
346
print(search_url)
347
348
# Pagination through query updates
349
page_2 = search_url.update_query({'page': 2})
350
page_3 = search_url.update_query({'page': 3, 'per_page': 50})
351
352
# Filter refinement by extending
353
refined = search_url.extend_query({'language': 'en', 'format': 'json'})
354
```
355
356
### Query Parameter Encoding
357
358
```python
359
from yarl import URL
360
361
url = URL('https://example.com/')
362
363
# Special characters are automatically encoded
364
special_chars = url.with_query({
365
'message': 'Hello, World!',
366
'symbols': '$%&=+',
367
'unicode': 'café résumé',
368
'spaces': 'value with spaces'
369
})
370
371
print(special_chars.raw_query_string) # Shows encoded version
372
print(special_chars.query_string) # Shows decoded version
373
374
# Access the raw vs decoded values
375
print(special_chars.query['unicode']) # 'café résumé' (decoded)
376
```