python-multipart 0.0.10__tar.gz → 0.0.12__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.
- {python_multipart-0.0.10 → python_multipart-0.0.12}/.gitignore +1 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/CHANGELOG.md +11 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/PKG-INFO +1 -1
- {python_multipart-0.0.10 → python_multipart-0.0.12}/multipart/__init__.py +1 -1
- {python_multipart-0.0.10 → python_multipart-0.0.12}/multipart/decoders.py +19 -6
- {python_multipart-0.0.10 → python_multipart-0.0.12}/multipart/multipart.py +168 -148
- {python_multipart-0.0.10 → python_multipart-0.0.12}/pyproject.toml +6 -1
- python_multipart-0.0.12/tests/__init__.py +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/compat.py +17 -9
- python_multipart-0.0.12/tests/test_data/http/CRLF_in_header.http +6 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/CR_in_header.yaml +1 -1
- python_multipart-0.0.12/tests/test_data/http/bad_header_char.yaml +3 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_multipart.py +216 -173
- {python_multipart-0.0.10 → python_multipart-0.0.12}/LICENSE.txt +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/README.md +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/multipart/exceptions.py +0 -0
- /python_multipart-0.0.10/tests/__init__.py → /python_multipart-0.0.12/multipart/py.typed +0 -0
- /python_multipart-0.0.10/tests/test_data/http/bad_header_char.yaml → /python_multipart-0.0.12/tests/test_data/http/CRLF_in_header.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/CR_in_header.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/CR_in_header_value.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/CR_in_header_value.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/almost_match_boundary.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/almost_match_boundary.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/almost_match_boundary_without_CR.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/almost_match_boundary_without_CR.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/almost_match_boundary_without_LF.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/almost_match_boundary_without_LF.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/almost_match_boundary_without_final_hyphen.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/almost_match_boundary_without_final_hyphen.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/bad_end_of_headers.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/bad_end_of_headers.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/bad_header_char.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/bad_initial_boundary.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/bad_initial_boundary.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/base64_encoding.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/base64_encoding.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/empty_header.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/empty_header.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/header_with_number.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/header_with_number.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/mixed_plain_and_base64_encoding.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/mixed_plain_and_base64_encoding.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/multiple_fields.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/multiple_fields.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/multiple_files.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/multiple_files.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/quoted_printable_encoding.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/quoted_printable_encoding.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_field.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_field.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_field_blocks.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_field_blocks.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_field_longer.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_field_longer.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_field_single_file.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_field_single_file.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_field_with_leading_newlines.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_field_with_leading_newlines.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_file.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/single_file.yaml +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/utf8_filename.http +0 -0
- {python_multipart-0.0.10 → python_multipart-0.0.12}/tests/test_data/http/utf8_filename.yaml +0 -0
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.0.12 (2024-09-29)
|
|
4
|
+
|
|
5
|
+
* Improve error message when boundary character does not match [#124](https://github.com/Kludex/python-multipart/pull/124).
|
|
6
|
+
* Add mypy strict typing [#140](https://github.com/Kludex/python-multipart/pull/140).
|
|
7
|
+
* Enforce 100% coverage [#159](https://github.com/Kludex/python-multipart/pull/159).
|
|
8
|
+
|
|
9
|
+
## 0.0.11 (2024-09-28)
|
|
10
|
+
|
|
11
|
+
* Improve performance, especially in data with many CR-LF [#137](https://github.com/Kludex/python-multipart/pull/137).
|
|
12
|
+
* Handle invalid CRLF in header name [#141](https://github.com/Kludex/python-multipart/pull/141).
|
|
13
|
+
|
|
3
14
|
## 0.0.10 (2024-09-21)
|
|
4
15
|
|
|
5
16
|
* Support `on_header_begin` [#103](https://github.com/Kludex/python-multipart/pull/103).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: python-multipart
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.12
|
|
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/
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
import binascii
|
|
3
|
-
from
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from .exceptions import DecodeError
|
|
6
6
|
|
|
7
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
8
|
+
from typing import Protocol, TypeVar
|
|
9
|
+
|
|
10
|
+
_T_contra = TypeVar("_T_contra", contravariant=True)
|
|
11
|
+
|
|
12
|
+
class SupportsWrite(Protocol[_T_contra]):
|
|
13
|
+
def write(self, __b: _T_contra) -> object: ...
|
|
14
|
+
|
|
15
|
+
# No way to specify optional methods. See
|
|
16
|
+
# https://github.com/python/typing/issues/601
|
|
17
|
+
# close() [Optional]
|
|
18
|
+
# finalize() [Optional]
|
|
19
|
+
|
|
7
20
|
|
|
8
21
|
class Base64Decoder:
|
|
9
22
|
"""This object provides an interface to decode a stream of Base64 data. It
|
|
@@ -34,7 +47,7 @@ class Base64Decoder:
|
|
|
34
47
|
:param underlying: the underlying object to pass writes to
|
|
35
48
|
"""
|
|
36
49
|
|
|
37
|
-
def __init__(self, underlying:
|
|
50
|
+
def __init__(self, underlying: "SupportsWrite[bytes]") -> None:
|
|
38
51
|
self.cache = bytearray()
|
|
39
52
|
self.underlying = underlying
|
|
40
53
|
|
|
@@ -67,9 +80,9 @@ class Base64Decoder:
|
|
|
67
80
|
# Get the remaining bytes and save in our cache.
|
|
68
81
|
remaining_len = len(data) % 4
|
|
69
82
|
if remaining_len > 0:
|
|
70
|
-
self.cache = data[-remaining_len:]
|
|
83
|
+
self.cache[:] = data[-remaining_len:]
|
|
71
84
|
else:
|
|
72
|
-
self.cache = b""
|
|
85
|
+
self.cache[:] = b""
|
|
73
86
|
|
|
74
87
|
# Return the length of the data to indicate no error.
|
|
75
88
|
return len(data)
|
|
@@ -112,7 +125,7 @@ class QuotedPrintableDecoder:
|
|
|
112
125
|
:param underlying: the underlying object to pass writes to
|
|
113
126
|
"""
|
|
114
127
|
|
|
115
|
-
def __init__(self, underlying:
|
|
128
|
+
def __init__(self, underlying: "SupportsWrite[bytes]") -> None:
|
|
116
129
|
self.cache = b""
|
|
117
130
|
self.underlying = underlying
|
|
118
131
|
|
|
@@ -160,7 +173,7 @@ class QuotedPrintableDecoder:
|
|
|
160
173
|
call it.
|
|
161
174
|
"""
|
|
162
175
|
# If we have a cache, write and then remove it.
|
|
163
|
-
if len(self.cache) > 0:
|
|
176
|
+
if len(self.cache) > 0: # pragma: no cover
|
|
164
177
|
self.underlying.write(binascii.a2b_qp(self.cache))
|
|
165
178
|
self.cache = b""
|
|
166
179
|
|