python-multipart 0.0.12__tar.gz → 0.0.13__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.
Files changed (64) hide show
  1. {python_multipart-0.0.12 → python_multipart-0.0.13}/CHANGELOG.md +4 -0
  2. {python_multipart-0.0.12 → python_multipart-0.0.13}/PKG-INFO +1 -10
  3. {python_multipart-0.0.12 → python_multipart-0.0.13}/README.md +0 -9
  4. python_multipart-0.0.13/_python_multipart.pth +1 -0
  5. python_multipart-0.0.13/_python_multipart_loader.py +37 -0
  6. {python_multipart-0.0.12 → python_multipart-0.0.13}/pyproject.toml +9 -5
  7. {python_multipart-0.0.12/multipart → python_multipart-0.0.13/python_multipart}/__init__.py +1 -1
  8. {python_multipart-0.0.12/multipart → python_multipart-0.0.13/python_multipart}/decoders.py +4 -4
  9. {python_multipart-0.0.12/multipart → python_multipart-0.0.13/python_multipart}/multipart.py +6 -6
  10. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_multipart.py +10 -4
  11. {python_multipart-0.0.12 → python_multipart-0.0.13}/.gitignore +0 -0
  12. {python_multipart-0.0.12 → python_multipart-0.0.13}/LICENSE.txt +0 -0
  13. {python_multipart-0.0.12/multipart → python_multipart-0.0.13/python_multipart}/exceptions.py +0 -0
  14. {python_multipart-0.0.12/multipart → python_multipart-0.0.13/python_multipart}/py.typed +0 -0
  15. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/__init__.py +0 -0
  16. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/compat.py +0 -0
  17. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/CRLF_in_header.http +0 -0
  18. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/CRLF_in_header.yaml +0 -0
  19. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/CR_in_header.http +0 -0
  20. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/CR_in_header.yaml +0 -0
  21. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/CR_in_header_value.http +0 -0
  22. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/CR_in_header_value.yaml +0 -0
  23. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/almost_match_boundary.http +0 -0
  24. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/almost_match_boundary.yaml +0 -0
  25. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/almost_match_boundary_without_CR.http +0 -0
  26. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/almost_match_boundary_without_CR.yaml +0 -0
  27. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/almost_match_boundary_without_LF.http +0 -0
  28. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/almost_match_boundary_without_LF.yaml +0 -0
  29. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/almost_match_boundary_without_final_hyphen.http +0 -0
  30. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/almost_match_boundary_without_final_hyphen.yaml +0 -0
  31. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/bad_end_of_headers.http +0 -0
  32. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/bad_end_of_headers.yaml +0 -0
  33. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/bad_header_char.http +0 -0
  34. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/bad_header_char.yaml +0 -0
  35. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/bad_initial_boundary.http +0 -0
  36. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/bad_initial_boundary.yaml +0 -0
  37. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/base64_encoding.http +0 -0
  38. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/base64_encoding.yaml +0 -0
  39. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/empty_header.http +0 -0
  40. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/empty_header.yaml +0 -0
  41. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/header_with_number.http +0 -0
  42. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/header_with_number.yaml +0 -0
  43. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/mixed_plain_and_base64_encoding.http +0 -0
  44. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/mixed_plain_and_base64_encoding.yaml +0 -0
  45. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/multiple_fields.http +0 -0
  46. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/multiple_fields.yaml +0 -0
  47. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/multiple_files.http +0 -0
  48. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/multiple_files.yaml +0 -0
  49. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/quoted_printable_encoding.http +0 -0
  50. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/quoted_printable_encoding.yaml +0 -0
  51. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_field.http +0 -0
  52. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_field.yaml +0 -0
  53. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_field_blocks.http +0 -0
  54. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_field_blocks.yaml +0 -0
  55. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_field_longer.http +0 -0
  56. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_field_longer.yaml +0 -0
  57. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_field_single_file.http +0 -0
  58. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_field_single_file.yaml +0 -0
  59. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_field_with_leading_newlines.http +0 -0
  60. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_field_with_leading_newlines.yaml +0 -0
  61. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_file.http +0 -0
  62. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/single_file.yaml +0 -0
  63. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/utf8_filename.http +0 -0
  64. {python_multipart-0.0.12 → python_multipart-0.0.13}/tests/test_data/http/utf8_filename.yaml +0 -0
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.0.13 (2024-10-20)
4
+
5
+ * Rename import to `python_multipart` [#166](https://github.com/Kludex/python-multipart/pull/166).
6
+
3
7
  ## 0.0.12 (2024-09-29)
4
8
 
5
9
  * Improve error message when boundary character does not match [#124](https://github.com/Kludex/python-multipart/pull/124).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: python-multipart
3
- Version: 0.0.12
3
+ Version: 0.0.13
4
4
  Summary: A streaming multipart parser for Python
5
5
  Project-URL: Homepage, https://github.com/Kludex/python-multipart
6
6
  Project-URL: Documentation, https://kludex.github.io/python-multipart/
@@ -38,12 +38,3 @@ Test coverage is currently 100%.
38
38
  ## Why?
39
39
 
40
40
  Because streaming uploads are awesome for large files.
41
-
42
- ## How to Test
43
-
44
- If you want to test:
45
-
46
- ```bash
47
- $ pip install '.[dev]'
48
- $ inv test
49
- ```
@@ -11,12 +11,3 @@ Test coverage is currently 100%.
11
11
  ## Why?
12
12
 
13
13
  Because streaming uploads are awesome for large files.
14
-
15
- ## How to Test
16
-
17
- If you want to test:
18
-
19
- ```bash
20
- $ pip install '.[dev]'
21
- $ inv test
22
- ```
@@ -0,0 +1 @@
1
+ import _python_multipart_loader
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ # The purpose of this file is to allow `import multipart` to continue to work
4
+ # unless `multipart` (the PyPI package) is also installed, in which case
5
+ # a collision is avoided, and `import multipart` is no longer injected.
6
+ import importlib
7
+ import importlib.abc
8
+ import importlib.machinery
9
+ import importlib.util
10
+ import sys
11
+ import warnings
12
+
13
+
14
+ class PythonMultipartCompatFinder(importlib.abc.MetaPathFinder):
15
+ def find_spec(
16
+ self, fullname: str, path: object = None, target: object = None
17
+ ) -> importlib.machinery.ModuleSpec | None:
18
+ if fullname != "multipart":
19
+ return None
20
+ old_sys_meta_path = sys.meta_path
21
+ try:
22
+ sys.meta_path = [p for p in sys.meta_path if not isinstance(p, type(self))]
23
+ if multipart := importlib.util.find_spec("multipart"):
24
+ return multipart
25
+
26
+ warnings.warn("Please use `import python_multipart` instead.", FutureWarning, stacklevel=2)
27
+ sys.modules["multipart"] = importlib.import_module("python_multipart")
28
+ return importlib.util.find_spec("python_multipart")
29
+ finally:
30
+ sys.meta_path = old_sys_meta_path
31
+
32
+
33
+ def install() -> None:
34
+ sys.meta_path.insert(0, PythonMultipartCompatFinder())
35
+
36
+
37
+ install()
@@ -55,6 +55,9 @@ dev-dependencies = [
55
55
  "mkdocs-autorefs",
56
56
  ]
57
57
 
58
+ [tool.uv.pip]
59
+ reinstall-package = ["python-multipart"]
60
+
58
61
  [project.urls]
59
62
  Homepage = "https://github.com/Kludex/python-multipart"
60
63
  Documentation = "https://kludex.github.io/python-multipart/"
@@ -62,13 +65,14 @@ Changelog = "https://github.com/Kludex/python-multipart/blob/master/CHANGELOG.md
62
65
  Source = "https://github.com/Kludex/python-multipart"
63
66
 
64
67
  [tool.hatch.version]
65
- path = "multipart/__init__.py"
66
-
67
- [tool.hatch.build.targets.wheel]
68
- packages = ["multipart"]
68
+ path = "python_multipart/__init__.py"
69
69
 
70
70
  [tool.hatch.build.targets.sdist]
71
- include = ["/multipart", "/tests", "CHANGELOG.md", "LICENSE.txt"]
71
+ include = ["/python_multipart", "/tests", "CHANGELOG.md", "LICENSE.txt", "_python_multipart.pth", "_python_multipart_loader.py"]
72
+
73
+ [tool.hatch.build.targets.wheel.force-include]
74
+ "_python_multipart.pth" = "_python_multipart.pth"
75
+ "_python_multipart_loader.py" = "_python_multipart_loader.py"
72
76
 
73
77
  [tool.mypy]
74
78
  strict = true
@@ -2,7 +2,7 @@
2
2
  __author__ = "Andrew Dunham"
3
3
  __license__ = "Apache"
4
4
  __copyright__ = "Copyright (c) 2012-2013, Andrew Dunham"
5
- __version__ = "0.0.12"
5
+ __version__ = "0.0.13"
6
6
 
7
7
  from .multipart import (
8
8
  BaseParser,
@@ -25,7 +25,7 @@ class Base64Decoder:
25
25
  call write() on the underlying object. This is primarily used for decoding
26
26
  form data encoded as Base64, but can be used for other purposes::
27
27
 
28
- from multipart.decoders import Base64Decoder
28
+ from python_multipart.decoders import Base64Decoder
29
29
  fd = open("notb64.txt", "wb")
30
30
  decoder = Base64Decoder(fd)
31
31
  try:
@@ -55,7 +55,7 @@ class Base64Decoder:
55
55
  """Takes any input data provided, decodes it as base64, and passes it
56
56
  on to the underlying object. If the data provided is invalid base64
57
57
  data, then this method will raise
58
- a :class:`multipart.exceptions.DecodeError`
58
+ a :class:`python_multipart.exceptions.DecodeError`
59
59
 
60
60
  :param data: base64 data to decode
61
61
  """
@@ -97,7 +97,7 @@ class Base64Decoder:
97
97
  def finalize(self) -> None:
98
98
  """Finalize this object. This should be called when no more data
99
99
  should be written to the stream. This function can raise a
100
- :class:`multipart.exceptions.DecodeError` if there is some remaining
100
+ :class:`python_multipart.exceptions.DecodeError` if there is some remaining
101
101
  data in the cache.
102
102
 
103
103
  If the underlying object has a `finalize()` method, this function will
@@ -118,7 +118,7 @@ class Base64Decoder:
118
118
  class QuotedPrintableDecoder:
119
119
  """This object provides an interface to decode a stream of quoted-printable
120
120
  data. It is instantiated with an "underlying object", in the same manner
121
- as the :class:`multipart.decoders.Base64Decoder` class. This class behaves
121
+ as the :class:`python_multipart.decoders.Base64Decoder` class. This class behaves
122
122
  in exactly the same way, including maintaining a cache of quoted-printable
123
123
  chunks.
124
124
 
@@ -241,7 +241,7 @@ class Field:
241
241
  value: the value of the form field - either a bytestring or None.
242
242
 
243
243
  Returns:
244
- A new instance of a [`Field`][multipart.Field].
244
+ A new instance of a [`Field`][python_multipart.Field].
245
245
  """
246
246
 
247
247
  f = cls(name)
@@ -351,7 +351,7 @@ class File:
351
351
  | MAX_MEMORY_FILE_SIZE | `int` | 1 MiB | The maximum number of bytes of a File to keep in memory. By default, the contents of a File are kept into memory until a certain limit is reached, after which the contents of the File are written to a temporary file. This behavior can be disabled by setting this value to an appropriately large value (or, for example, infinity, such as `float('inf')`. |
352
352
 
353
353
  Args:
354
- file_name: The name of the file that this [`File`][multipart.File] represents.
354
+ file_name: The name of the file that this [`File`][python_multipart.File] represents.
355
355
  field_name: The name of the form field that this file was uploaded with. This can be None, if, for example,
356
356
  the file was uploaded with Content-Type application/octet-stream.
357
357
  config: The configuration for this File. See above for valid configuration keys and their corresponding values.
@@ -663,7 +663,7 @@ class OctetStreamParser(BaseParser):
663
663
  | on_end | None | Called when the parser is finished parsing all data.|
664
664
 
665
665
  Args:
666
- callbacks: A dictionary of callbacks. See the documentation for [`BaseParser`][multipart.BaseParser].
666
+ callbacks: A dictionary of callbacks. See the documentation for [`BaseParser`][python_multipart.BaseParser].
667
667
  max_size: The maximum size of body to parse. Defaults to infinity - i.e. unbounded.
668
668
  """
669
669
 
@@ -733,12 +733,12 @@ class QuerystringParser(BaseParser):
733
733
  | on_end | None | Called when the parser is finished parsing all data.|
734
734
 
735
735
  Args:
736
- callbacks: A dictionary of callbacks. See the documentation for [`BaseParser`][multipart.BaseParser].
736
+ callbacks: A dictionary of callbacks. See the documentation for [`BaseParser`][python_multipart.BaseParser].
737
737
  strict_parsing: Whether or not to parse the body strictly. Defaults to False. If this is set to True, then the
738
738
  behavior of the parser changes as the following: if a field has a value with an equal sign
739
739
  (e.g. "foo=bar", or "foo="), it is always included. If a field has no equals sign (e.g. "...&name&..."),
740
740
  it will be treated as an error if 'strict_parsing' is True, otherwise included. If an error is encountered,
741
- then a [`QuerystringParseError`][multipart.exceptions.QuerystringParseError] will be raised.
741
+ then a [`QuerystringParseError`][python_multipart.exceptions.QuerystringParseError] will be raised.
742
742
  max_size: The maximum size of body to parse. Defaults to infinity - i.e. unbounded.
743
743
  """ # noqa: E501
744
744
 
@@ -969,7 +969,7 @@ class MultipartParser(BaseParser):
969
969
 
970
970
  Args:
971
971
  boundary: The multipart boundary. This is required, and must match what is given in the HTTP request - usually in the Content-Type header.
972
- callbacks: A dictionary of callbacks. See the documentation for [`BaseParser`][multipart.BaseParser].
972
+ callbacks: A dictionary of callbacks. See the documentation for [`BaseParser`][python_multipart.BaseParser].
973
973
  max_size: The maximum size of body to parse. Defaults to infinity - i.e. unbounded.
974
974
  """ # noqa: E501
975
975
 
@@ -11,9 +11,15 @@ from unittest.mock import Mock
11
11
 
12
12
  import yaml
13
13
 
14
- from multipart.decoders import Base64Decoder, QuotedPrintableDecoder
15
- from multipart.exceptions import DecodeError, FileError, FormParserError, MultipartParseError, QuerystringParseError
16
- from multipart.multipart import (
14
+ from python_multipart.decoders import Base64Decoder, QuotedPrintableDecoder
15
+ from python_multipart.exceptions import (
16
+ DecodeError,
17
+ FileError,
18
+ FormParserError,
19
+ MultipartParseError,
20
+ QuerystringParseError,
21
+ )
22
+ from python_multipart.multipart import (
17
23
  BaseParser,
18
24
  Field,
19
25
  File,
@@ -31,7 +37,7 @@ from .compat import parametrize, parametrize_class
31
37
  if TYPE_CHECKING:
32
38
  from typing import Any, Iterator, TypedDict
33
39
 
34
- from multipart.multipart import FieldProtocol, FileConfig, FileProtocol
40
+ from python_multipart.multipart import FieldProtocol, FileConfig, FileProtocol
35
41
 
36
42
  class TestParams(TypedDict):
37
43
  name: str