python-http_request 0.1.3__tar.gz → 0.1.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-http_request
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: Python http response utils.
5
5
  Home-page: https://github.com/ChenyangGao/python-modules/tree/main/python-http_request
6
6
  License: MIT
@@ -20,10 +20,10 @@ Classifier: Programming Language :: Python :: 3 :: Only
20
20
  Classifier: Topic :: Software Development
21
21
  Classifier: Topic :: Software Development :: Libraries
22
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
- Requires-Dist: http_response (>=0.0.7)
23
+ Requires-Dist: http_response (>=0.0.9)
24
24
  Requires-Dist: orjson
25
25
  Requires-Dist: python-asynctools (>=0.1.3)
26
- Requires-Dist: python-dicttools (>=0.0.2)
26
+ Requires-Dist: python-dicttools (>=0.0.4)
27
27
  Requires-Dist: python-ensure (>=0.0.1)
28
28
  Requires-Dist: python-filewrap (>=0.2.8)
29
29
  Requires-Dist: python-texttools (>=0.0.4)
@@ -2,7 +2,7 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  __author__ = "ChenyangGao <https://chenyanggao.github.io>"
5
- __version__ = (0, 1, 3)
5
+ __version__ = (0, 1, 5)
6
6
  __all__ = [
7
7
  "SupportsGeturl", "url_origin", "complete_url", "ensure_ascii_url",
8
8
  "urlencode", "cookies_str_to_dict", "headers_str_to_dict_by_lines",
@@ -12,7 +12,7 @@ __all__ = [
12
12
 
13
13
  from collections import UserString
14
14
  from collections.abc import (
15
- AsyncIterable, AsyncIterator, Buffer, Iterable, Iterator,
15
+ AsyncIterable, AsyncIterator, Buffer, Callable, Iterable, Iterator,
16
16
  Mapping, Sequence,
17
17
  )
18
18
  from decimal import Decimal
@@ -35,7 +35,7 @@ from yarl import URL
35
35
 
36
36
  from asynctools import async_map
37
37
  from dicttools import dict_map, iter_items
38
- from ensure import ensure_bytes, ensure_buffer, ensure_str
38
+ from ensure import ensure_bytes as ensure_bytes_, ensure_buffer, ensure_str
39
39
  from filewrap import bio_chunk_iter, bio_chunk_async_iter, SupportsRead
40
40
  from http_response import get_charset, get_mimetype
41
41
  from orjson import dumps as json_dumps
@@ -82,7 +82,7 @@ def complete_url(
82
82
  url: str,
83
83
  /,
84
84
  default_port: int = 0,
85
- clean: bool = False,
85
+ params: Any = None,
86
86
  ) -> str:
87
87
  if url.startswith("/"):
88
88
  url = "http://localhost" + url
@@ -90,15 +90,12 @@ def complete_url(
90
90
  url = "http:" + url
91
91
  elif url.startswith("://"):
92
92
  url = "http" + url
93
- if not (clean or default_port):
93
+ if not (params or default_port):
94
94
  if not CRE_URL_SCHEME_match(url):
95
95
  url = "http://" + url
96
96
  return url
97
97
  urlp = urlparse(url)
98
- if clean:
99
- repl = {"params": "", "query": "", "fragment": ""}
100
- else:
101
- repl = {}
98
+ repl = {}
102
99
  if not urlp.scheme:
103
100
  repl["scheme"] = "http"
104
101
  netloc = urlp.netloc
@@ -108,6 +105,10 @@ def complete_url(
108
105
  netloc = netloc.removesuffix(":") + f":{default_port}"
109
106
  if netloc != urlp.netloc:
110
107
  repl["netloc"] = netloc
108
+ if params and (params := urlencode(params)):
109
+ if query := urlp.query:
110
+ params = query + "&" + params
111
+ repl["query"] = params
111
112
  if not repl:
112
113
  return url
113
114
  return urlunparse(urlp._replace(**repl)).rstrip("/")
@@ -200,6 +201,7 @@ def encode_multipart_data(
200
201
  files: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
201
202
  boundary: None | str = None,
202
203
  file_suffix: str = "",
204
+ ensure_bytes: bool = False,
203
205
  *,
204
206
  async_: Literal[False] = False,
205
207
  ) -> tuple[dict, Iterator[Buffer]]:
@@ -210,6 +212,7 @@ def encode_multipart_data(
210
212
  files: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
211
213
  boundary: None | str = None,
212
214
  file_suffix: str = "",
215
+ ensure_bytes: bool = False,
213
216
  *,
214
217
  async_: Literal[True],
215
218
  ) -> tuple[dict, AsyncIterator[Buffer]]:
@@ -219,9 +222,14 @@ def encode_multipart_data(
219
222
  files: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
220
223
  boundary: None | str = None,
221
224
  file_suffix: str = "",
225
+ ensure_bytes: bool = False,
222
226
  *,
223
227
  async_: bool = False,
224
228
  ) -> tuple[dict, Iterator[Buffer]] | tuple[dict, AsyncIterator[Buffer]]:
229
+ if ensure_bytes:
230
+ ensure_value: Callable = ensure_bytes_
231
+ else:
232
+ ensure_value = ensure_buffer
225
233
  if async_:
226
234
  return encode_multipart_data_async(data, files, boundary)
227
235
 
@@ -234,7 +242,7 @@ def encode_multipart_data(
234
242
  boundary_bytes = bytes(boundary)
235
243
  boundary = str(boundary_bytes, "latin-1")
236
244
  boundary_line = b"--%s\r\n" % boundary_bytes
237
- suffix = ensure_bytes(file_suffix)
245
+ suffix = ensure_bytes_(file_suffix)
238
246
  if suffix and not suffix.startswith(b"."):
239
247
  suffix = b"." + suffix
240
248
 
@@ -249,12 +257,12 @@ def encode_multipart_data(
249
257
  pass
250
258
  case [_, value, file_type]:
251
259
  if file_type:
252
- headers[b"content-type"] = ensure_bytes(file_type)
260
+ headers[b"content-type"] = ensure_bytes_(file_type)
253
261
  case [_, value, file_type, file_headers, *rest]:
254
262
  for k, v in iter_items(file_headers):
255
- headers[ensure_bytes(k).lower()] = ensure_bytes(v)
263
+ headers[ensure_bytes_(k).lower()] = ensure_bytes_(v)
256
264
  if file_type:
257
- headers[b"content-type"] = ensure_bytes(file_type)
265
+ headers[b"content-type"] = ensure_bytes_(file_type)
258
266
  if isinstance(value, (PathLike, SupportsRead)):
259
267
  is_file = True
260
268
  if isinstance(value, PathLike):
@@ -265,15 +273,15 @@ def encode_multipart_data(
265
273
  file = value
266
274
  value = bio_chunk_iter(file)
267
275
  if not filename:
268
- filename = ensure_bytes(basename(getattr(file, "name", b"") or b""))
276
+ filename = ensure_bytes_(basename(getattr(file, "name", b"") or b""))
269
277
  elif isinstance(value, Buffer):
270
278
  pass
271
279
  elif isinstance(value, (str, UserString)):
272
- value = ensure_bytes(value)
280
+ value = ensure_bytes_(value)
273
281
  elif isinstance(value, Iterable):
274
- value = map(ensure_buffer, value)
282
+ value = map(ensure_value, value)
275
283
  else:
276
- value = ensure_buffer(value)
284
+ value = ensure_value(value)
277
285
  if is_file:
278
286
  if filename:
279
287
  filename = bytes(quote(filename), "ascii")
@@ -282,7 +290,7 @@ def encode_multipart_data(
282
290
  else:
283
291
  filename = bytes(uuid4().hex, "ascii") + suffix
284
292
  if b"content-type" not in headers:
285
- headers[b"content-type"] = ensure_bytes(
293
+ headers[b"content-type"] = ensure_bytes_(
286
294
  guess_type(str(filename, "latin-1"))[0] or b"application/octet-stream")
287
295
  headers[b"content-disposition"] += b'; filename="%s"' % filename
288
296
  yield boundary_line
@@ -313,7 +321,12 @@ def encode_multipart_data_async(
313
321
  files: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
314
322
  boundary: None | str = None,
315
323
  file_suffix: str = "",
324
+ ensure_bytes: bool = False,
316
325
  ) -> tuple[dict, AsyncIterator[Buffer]]:
326
+ if ensure_bytes:
327
+ ensure_value: Callable = ensure_bytes_
328
+ else:
329
+ ensure_value = ensure_buffer
317
330
  if not boundary:
318
331
  boundary = uuid4().hex
319
332
  boundary_bytes = bytes(boundary, "ascii")
@@ -323,7 +336,7 @@ def encode_multipart_data_async(
323
336
  boundary_bytes = bytes(boundary)
324
337
  boundary = str(boundary_bytes, "latin-1")
325
338
  boundary_line = b"--%s\r\n" % boundary_bytes
326
- suffix = ensure_bytes(file_suffix)
339
+ suffix = ensure_bytes_(file_suffix)
327
340
  if suffix and not suffix.startswith(b"."):
328
341
  suffix = b"." + suffix
329
342
 
@@ -338,12 +351,12 @@ def encode_multipart_data_async(
338
351
  pass
339
352
  case [_, value, file_type]:
340
353
  if file_type:
341
- headers[b"content-type"] = ensure_bytes(file_type)
354
+ headers[b"content-type"] = ensure_bytes_(file_type)
342
355
  case [_, value, file_type, file_headers, *rest]:
343
356
  for k, v in iter_items(file_headers):
344
- headers[ensure_bytes(k).lower()] = ensure_bytes(v)
357
+ headers[ensure_bytes_(k).lower()] = ensure_bytes_(v)
345
358
  if file_type:
346
- headers[b"content-type"] = ensure_bytes(file_type)
359
+ headers[b"content-type"] = ensure_bytes_(file_type)
347
360
  if isinstance(value, (PathLike, SupportsRead)):
348
361
  is_file = True
349
362
  if isinstance(value, PathLike):
@@ -354,15 +367,15 @@ def encode_multipart_data_async(
354
367
  file = value
355
368
  value = bio_chunk_async_iter(file)
356
369
  if not filename:
357
- filename = ensure_bytes(basename(getattr(file, "name", b"") or b""))
370
+ filename = ensure_bytes_(basename(getattr(file, "name", b"") or b""))
358
371
  elif isinstance(value, Buffer):
359
372
  pass
360
373
  elif isinstance(value, (str, UserString)):
361
- value = ensure_bytes(value)
374
+ value = ensure_bytes_(value)
362
375
  elif isinstance(value, Iterable):
363
- value = async_map(ensure_buffer, value)
376
+ value = async_map(ensure_value, value)
364
377
  else:
365
- value = ensure_buffer(value)
378
+ value = ensure_value(value)
366
379
  if is_file:
367
380
  if filename:
368
381
  filename = bytes(quote(filename), "ascii")
@@ -371,7 +384,7 @@ def encode_multipart_data_async(
371
384
  else:
372
385
  filename = bytes(uuid4().hex, "ascii") + suffix
373
386
  if b"content-type" not in headers:
374
- headers[b"content-type"] = ensure_bytes(
387
+ headers[b"content-type"] = ensure_bytes_(
375
388
  guess_type(str(filename, "latin-1"))[0] or b"application/octet-stream")
376
389
  headers[b"content-disposition"] += b'; filename="%s"' % filename
377
390
  yield boundary_line
@@ -432,20 +445,20 @@ def normalize_request_args(
432
445
  files: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
433
446
  headers: None | Mapping[string, Any] | Iterable[tuple[string, Any]] = None,
434
447
  ensure_ascii: bool = True,
448
+ ensure_bytes: bool = False,
435
449
  *,
436
450
  async_: bool = False,
437
451
  ) -> RequestArgs:
452
+ if ensure_bytes:
453
+ ensure_value: Callable = ensure_bytes_
454
+ else:
455
+ ensure_value = ensure_buffer
438
456
  method = ensure_str(method).upper()
439
457
  if isinstance(url, SupportsGeturl):
440
458
  url = url.geturl()
441
459
  elif isinstance(url, URL):
442
460
  url = str(url)
443
- url = complete_url(ensure_str(url))
444
- if params and (params := urlencode(params, ensure_ascii=ensure_ascii)):
445
- urlp = urlparse(url)
446
- if query := urlp.query:
447
- params = query + "&" + params
448
- url = urlunparse(urlp._replace(query=params))
461
+ url = complete_url(ensure_str(url), params=params)
449
462
  if ensure_ascii:
450
463
  url = ensure_ascii_url(url)
451
464
  headers_ = dict_map(
@@ -466,15 +479,20 @@ def normalize_request_args(
466
479
  elif data is not None:
467
480
  if isinstance(data, Buffer):
468
481
  pass
482
+ elif isinstance(data, SupportsRead):
483
+ if async_:
484
+ data = bio_chunk_async_iter(data)
485
+ else:
486
+ data = bio_chunk_iter(data)
469
487
  elif isinstance(data, (str, UserString)):
470
488
  data = data.encode(charset)
471
489
  elif isinstance(data, AsyncIterable):
472
- data = async_map(ensure_buffer, data)
490
+ data = async_map(ensure_value, data)
473
491
  elif isinstance(data, Iterator):
474
492
  if async_:
475
- data = async_map(ensure_buffer, data)
493
+ data = async_map(ensure_value, data)
476
494
  else:
477
- data = map(ensure_buffer, data)
495
+ data = map(ensure_value, data)
478
496
  elif mimetype == "application/json":
479
497
  if charset == "utf-8":
480
498
  data = json_dumps(data, default=json_default)
@@ -491,13 +509,18 @@ def normalize_request_args(
491
509
  elif json is not None:
492
510
  if isinstance(json, Buffer):
493
511
  data = json
512
+ elif isinstance(json, SupportsRead):
513
+ if async_:
514
+ data = bio_chunk_async_iter(json)
515
+ else:
516
+ data = bio_chunk_iter(json)
494
517
  elif isinstance(json, AsyncIterable):
495
- data = async_map(ensure_buffer, json)
518
+ data = async_map(ensure_value, json)
496
519
  elif isinstance(json, Iterator):
497
520
  if async_:
498
- data = async_map(ensure_buffer, json)
521
+ data = async_map(ensure_value, json)
499
522
  else:
500
- data = map(ensure_buffer, json)
523
+ data = map(ensure_value, json)
501
524
  elif charset == "utf-8":
502
525
  data = json_dumps(json, default=json_default)
503
526
  else:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-http_request"
3
- version = "0.1.3"
3
+ version = "0.1.5"
4
4
  description = "Python http response utils."
5
5
  authors = ["ChenyangGao <wosiwujm@gmail.com>"]
6
6
  license = "MIT"
@@ -27,10 +27,10 @@ include = [
27
27
 
28
28
  [tool.poetry.dependencies]
29
29
  python = "^3.12"
30
- http_response = ">=0.0.7"
30
+ http_response = ">=0.0.9"
31
31
  orjson = "*"
32
32
  python-asynctools = ">=0.1.3"
33
- python-dicttools = ">=0.0.2"
33
+ python-dicttools = ">=0.0.4"
34
34
  python-ensure = ">=0.0.1"
35
35
  python-filewrap = ">=0.2.8"
36
36
  python-texttools = ">=0.0.4"