Загрузить файлы в «venv/Lib/site-packages/python_multipart»
This commit is contained in:
35
venv/Lib/site-packages/python_multipart/__init__.py
Normal file
35
venv/Lib/site-packages/python_multipart/__init__.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Copyright 2012, Andrew Dunham
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
__version__ = "0.0.32"
|
||||||
|
|
||||||
|
from .multipart import (
|
||||||
|
BaseParser,
|
||||||
|
FormParser,
|
||||||
|
MultipartParser,
|
||||||
|
OctetStreamParser,
|
||||||
|
QuerystringParser,
|
||||||
|
create_form_parser,
|
||||||
|
parse_form,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"BaseParser",
|
||||||
|
"FormParser",
|
||||||
|
"MultipartParser",
|
||||||
|
"OctetStreamParser",
|
||||||
|
"QuerystringParser",
|
||||||
|
"create_form_parser",
|
||||||
|
"parse_form",
|
||||||
|
)
|
||||||
185
venv/Lib/site-packages/python_multipart/decoders.py
Normal file
185
venv/Lib/site-packages/python_multipart/decoders.py
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
import base64
|
||||||
|
import binascii
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from .exceptions import DecodeError
|
||||||
|
|
||||||
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
|
from typing import Protocol, TypeVar
|
||||||
|
|
||||||
|
_T_contra = TypeVar("_T_contra", contravariant=True)
|
||||||
|
|
||||||
|
class SupportsWrite(Protocol[_T_contra]):
|
||||||
|
def write(self, __b: _T_contra) -> object: ...
|
||||||
|
|
||||||
|
# No way to specify optional methods. See
|
||||||
|
# https://github.com/python/typing/issues/601
|
||||||
|
# close() [Optional]
|
||||||
|
# finalize() [Optional]
|
||||||
|
|
||||||
|
|
||||||
|
class Base64Decoder:
|
||||||
|
"""This object provides an interface to decode a stream of Base64 data. It
|
||||||
|
is instantiated with an "underlying object", and whenever a write()
|
||||||
|
operation is performed, it will decode the incoming data as Base64, and
|
||||||
|
call write() on the underlying object. This is primarily used for decoding
|
||||||
|
form data encoded as Base64, but can be used for other purposes::
|
||||||
|
|
||||||
|
from python_multipart.decoders import Base64Decoder
|
||||||
|
fd = open("notb64.txt", "wb")
|
||||||
|
decoder = Base64Decoder(fd)
|
||||||
|
try:
|
||||||
|
decoder.write("Zm9vYmFy") # "foobar" in Base64
|
||||||
|
decoder.finalize()
|
||||||
|
finally:
|
||||||
|
decoder.close()
|
||||||
|
|
||||||
|
# The contents of "notb64.txt" should be "foobar".
|
||||||
|
|
||||||
|
This object will also pass all finalize() and close() calls to the
|
||||||
|
underlying object, if the underlying object supports them.
|
||||||
|
|
||||||
|
Note that this class maintains a cache of base64 chunks, so that a write of
|
||||||
|
arbitrary size can be performed. You must call :meth:`finalize` on this
|
||||||
|
object after all writes are completed to ensure that all data is flushed
|
||||||
|
to the underlying object.
|
||||||
|
|
||||||
|
:param underlying: the underlying object to pass writes to
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, underlying: "SupportsWrite[bytes]") -> None:
|
||||||
|
self.cache = bytearray()
|
||||||
|
self.underlying = underlying
|
||||||
|
|
||||||
|
def write(self, data: bytes) -> int:
|
||||||
|
"""Takes any input data provided, decodes it as base64, and passes it
|
||||||
|
on to the underlying object. If the data provided is invalid base64
|
||||||
|
data, then this method will raise
|
||||||
|
a :class:`python_multipart.exceptions.DecodeError`
|
||||||
|
|
||||||
|
:param data: base64 data to decode
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Prepend any cache info to our data.
|
||||||
|
if len(self.cache) > 0:
|
||||||
|
data = bytes(self.cache) + data
|
||||||
|
|
||||||
|
# Slice off a string that's a multiple of 4.
|
||||||
|
decode_len = (len(data) // 4) * 4
|
||||||
|
val = data[:decode_len]
|
||||||
|
|
||||||
|
# Decode and write, if we have any.
|
||||||
|
if len(val) > 0:
|
||||||
|
try:
|
||||||
|
decoded = base64.b64decode(val)
|
||||||
|
except binascii.Error:
|
||||||
|
raise DecodeError("There was an error raised while decoding base64-encoded data.")
|
||||||
|
|
||||||
|
self.underlying.write(decoded)
|
||||||
|
|
||||||
|
# Get the remaining bytes and save in our cache.
|
||||||
|
remaining_len = len(data) % 4
|
||||||
|
if remaining_len > 0:
|
||||||
|
self.cache[:] = data[-remaining_len:]
|
||||||
|
else:
|
||||||
|
self.cache[:] = b""
|
||||||
|
|
||||||
|
# Return the length of the data to indicate no error.
|
||||||
|
return len(data)
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
"""Close this decoder. If the underlying object has a `close()`
|
||||||
|
method, this function will call it.
|
||||||
|
"""
|
||||||
|
if hasattr(self.underlying, "close"):
|
||||||
|
self.underlying.close()
|
||||||
|
|
||||||
|
def finalize(self) -> None:
|
||||||
|
"""Finalize this object. This should be called when no more data
|
||||||
|
should be written to the stream. This function can raise a
|
||||||
|
:class:`python_multipart.exceptions.DecodeError` if there is some remaining
|
||||||
|
data in the cache.
|
||||||
|
|
||||||
|
If the underlying object has a `finalize()` method, this function will
|
||||||
|
call it.
|
||||||
|
"""
|
||||||
|
if len(self.cache) > 0:
|
||||||
|
raise DecodeError(
|
||||||
|
"There are %d bytes remaining in the Base64Decoder cache when finalize() is called" % len(self.cache)
|
||||||
|
)
|
||||||
|
|
||||||
|
if hasattr(self.underlying, "finalize"):
|
||||||
|
self.underlying.finalize()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"{self.__class__.__name__}(underlying={self.underlying!r})"
|
||||||
|
|
||||||
|
|
||||||
|
class QuotedPrintableDecoder:
|
||||||
|
"""This object provides an interface to decode a stream of quoted-printable
|
||||||
|
data. It is instantiated with an "underlying object", in the same manner
|
||||||
|
as the :class:`python_multipart.decoders.Base64Decoder` class. This class behaves
|
||||||
|
in exactly the same way, including maintaining a cache of quoted-printable
|
||||||
|
chunks.
|
||||||
|
|
||||||
|
:param underlying: the underlying object to pass writes to
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, underlying: "SupportsWrite[bytes]") -> None:
|
||||||
|
self.cache = b""
|
||||||
|
self.underlying = underlying
|
||||||
|
|
||||||
|
def write(self, data: bytes) -> int:
|
||||||
|
"""Takes any input data provided, decodes it as quoted-printable, and
|
||||||
|
passes it on to the underlying object.
|
||||||
|
|
||||||
|
:param data: quoted-printable data to decode
|
||||||
|
"""
|
||||||
|
# Prepend any cache info to our data.
|
||||||
|
if len(self.cache) > 0:
|
||||||
|
data = self.cache + data
|
||||||
|
|
||||||
|
# If the last 2 characters have an '=' sign in it, then we won't be
|
||||||
|
# able to decode the encoded value and we'll need to save it for the
|
||||||
|
# next decoding step.
|
||||||
|
if data[-2:].find(b"=") != -1:
|
||||||
|
enc, rest = data[:-2], data[-2:]
|
||||||
|
else:
|
||||||
|
enc = data
|
||||||
|
rest = b""
|
||||||
|
|
||||||
|
# Encode and write, if we have data.
|
||||||
|
if len(enc) > 0:
|
||||||
|
self.underlying.write(binascii.a2b_qp(enc))
|
||||||
|
|
||||||
|
# Save remaining in cache.
|
||||||
|
self.cache = rest
|
||||||
|
return len(data)
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
"""Close this decoder. If the underlying object has a `close()`
|
||||||
|
method, this function will call it.
|
||||||
|
"""
|
||||||
|
if hasattr(self.underlying, "close"):
|
||||||
|
self.underlying.close()
|
||||||
|
|
||||||
|
def finalize(self) -> None:
|
||||||
|
"""Finalize this object. This should be called when no more data
|
||||||
|
should be written to the stream. This function will not raise any
|
||||||
|
exceptions, but it may write more data to the underlying object if
|
||||||
|
there is data remaining in the cache.
|
||||||
|
|
||||||
|
If the underlying object has a `finalize()` method, this function will
|
||||||
|
call it.
|
||||||
|
"""
|
||||||
|
# If we have a cache, write and then remove it.
|
||||||
|
if len(self.cache) > 0: # pragma: no cover
|
||||||
|
self.underlying.write(binascii.a2b_qp(self.cache))
|
||||||
|
self.cache = b""
|
||||||
|
|
||||||
|
# Finalize our underlying stream.
|
||||||
|
if hasattr(self.underlying, "finalize"):
|
||||||
|
self.underlying.finalize()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"{self.__class__.__name__}(underlying={self.underlying!r})"
|
||||||
34
venv/Lib/site-packages/python_multipart/exceptions.py
Normal file
34
venv/Lib/site-packages/python_multipart/exceptions.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
class FormParserError(ValueError):
|
||||||
|
"""Base error class for our form parser."""
|
||||||
|
|
||||||
|
|
||||||
|
class ParseError(FormParserError):
|
||||||
|
"""This exception (or a subclass) is raised when there is an error while
|
||||||
|
parsing something.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, message: str, *, offset: int = -1) -> None:
|
||||||
|
super().__init__(message)
|
||||||
|
self.offset = offset
|
||||||
|
|
||||||
|
|
||||||
|
class MultipartParseError(ParseError):
|
||||||
|
"""This is a specific error that is raised when the MultipartParser detects
|
||||||
|
an error while parsing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class QuerystringParseError(ParseError):
|
||||||
|
"""This is a specific error that is raised when the QuerystringParser
|
||||||
|
detects an error while parsing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class DecodeError(ParseError):
|
||||||
|
"""This exception is raised when there is a decoding error - for example
|
||||||
|
with the Base64Decoder or QuotedPrintableDecoder.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class FileError(FormParserError, OSError):
|
||||||
|
"""Exception class for problems with the File class."""
|
||||||
1925
venv/Lib/site-packages/python_multipart/multipart.py
Normal file
1925
venv/Lib/site-packages/python_multipart/multipart.py
Normal file
File diff suppressed because it is too large
Load Diff
BIN
venv/Lib/site-packages/python_multipart/py.typed
Normal file
BIN
venv/Lib/site-packages/python_multipart/py.typed
Normal file
Binary file not shown.
Reference in New Issue
Block a user