update to python fastpi

This commit is contained in:
Iliyan Angelov
2025-11-16 15:59:05 +02:00
parent 93d4c1df80
commit 98ccd5b6ff
4464 changed files with 773233 additions and 13740 deletions

View File

@@ -0,0 +1,15 @@
# This is the canonical package information.
__author__ = 'Andrew Dunham'
__license__ = 'Apache'
__copyright__ = "Copyright (c) 2012-2013, Andrew Dunham"
__version__ = "0.0.6"
from .multipart import (
FormParser,
MultipartParser,
QuerystringParser,
OctetStreamParser,
create_form_parser,
parse_form,
)

View File

@@ -0,0 +1,171 @@
import base64
import binascii
from .exceptions import DecodeError
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 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):
self.cache = bytearray()
self.underlying = underlying
def write(self, data):
"""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:`multipart.exceptions.DecodeError`
:param data: base64 data to decode
"""
# Prepend any cache info to our data.
if len(self.cache) > 0:
data = 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):
"""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):
"""Finalize this object. This should be called when no more data
should be written to the stream. This function can raise a
:class:`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):
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:`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):
self.cache = b''
self.underlying = underlying
def write(self, data):
"""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):
"""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):
"""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:
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):
return f"{self.__class__.__name__}(underlying={self.underlying!r})"

View File

@@ -0,0 +1,46 @@
class FormParserError(ValueError):
"""Base error class for our form parser."""
pass
class ParseError(FormParserError):
"""This exception (or a subclass) is raised when there is an error while
parsing something.
"""
#: This is the offset in the input data chunk (*NOT* the overall stream) in
#: which the parse error occurred. It will be -1 if not specified.
offset = -1
class MultipartParseError(ParseError):
"""This is a specific error that is raised when the MultipartParser detects
an error while parsing.
"""
pass
class QuerystringParseError(ParseError):
"""This is a specific error that is raised when the QuerystringParser
detects an error while parsing.
"""
pass
class DecodeError(ParseError):
"""This exception is raised when there is a decoding error - for example
with the Base64Decoder or QuotedPrintableDecoder.
"""
pass
# On Python 3.3, IOError is the same as OSError, so we don't want to inherit
# from both of them. We handle this case below.
if IOError is not OSError: # pragma: no cover
class FileError(FormParserError, IOError, OSError):
"""Exception class for problems with the File class."""
pass
else: # pragma: no cover
class FileError(FormParserError, OSError):
"""Exception class for problems with the File class."""
pass

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,133 @@
import os
import re
import sys
import types
import functools
def ensure_in_path(path):
"""
Ensure that a given path is in the sys.path array
"""
if not os.path.isdir(path):
raise RuntimeError('Tried to add nonexisting path')
def _samefile(x, y):
try:
return os.path.samefile(x, y)
except OSError:
return False
except AttributeError:
# Probably on Windows.
path1 = os.path.abspath(x).lower()
path2 = os.path.abspath(y).lower()
return path1 == path2
# Remove existing copies of it.
for pth in sys.path:
if _samefile(pth, path):
sys.path.remove(pth)
# Add it at the beginning.
sys.path.insert(0, path)
# Check if pytest is imported. If so, we use it to create marking decorators.
# If not, we just create a function that does nothing.
try:
import pytest
except ImportError:
pytest = None
if pytest is not None:
slow_test = pytest.mark.slow_test
xfail = pytest.mark.xfail
else:
slow_test = lambda x: x
def xfail(*args, **kwargs):
if len(args) > 0 and isinstance(args[0], types.FunctionType):
return args[0]
return lambda x: x
# We don't use the pytest parametrizing function, since it seems to break
# with unittest.TestCase subclasses.
def parametrize(field_names, field_values):
# If we're not given a list of field names, we make it.
if not isinstance(field_names, (tuple, list)):
field_names = (field_names,)
field_values = [(val,) for val in field_values]
# Create a decorator that saves this list of field names and values on the
# function for later parametrizing.
def decorator(func):
func.__dict__['param_names'] = field_names
func.__dict__['param_values'] = field_values
return func
return decorator
# This is a metaclass that actually performs the parametrization.
class ParametrizingMetaclass(type):
IDENTIFIER_RE = re.compile('[^A-Za-z0-9]')
def __new__(klass, name, bases, attrs):
new_attrs = attrs.copy()
for attr_name, attr in attrs.items():
# We only care about functions
if not isinstance(attr, types.FunctionType):
continue
param_names = attr.__dict__.pop('param_names', None)
param_values = attr.__dict__.pop('param_values', None)
if param_names is None or param_values is None:
continue
# Create multiple copies of the function.
for i, values in enumerate(param_values):
assert len(param_names) == len(values)
# Get a repr of the values, and fix it to be a valid identifier
human = '_'.join(
[klass.IDENTIFIER_RE.sub('', repr(x)) for x in values]
)
# Create a new name.
# new_name = attr.__name__ + "_%d" % i
new_name = attr.__name__ + "__" + human
# Create a replacement function.
def create_new_func(func, names, values):
# Create a kwargs dictionary.
kwargs = dict(zip(names, values))
@functools.wraps(func)
def new_func(self):
return func(self, **kwargs)
# Manually set the name and return the new function.
new_func.__name__ = new_name
return new_func
# Actually create the new function.
new_func = create_new_func(attr, param_names, values)
# Save this new function in our attrs dict.
new_attrs[new_name] = new_func
# Remove the old attribute from our new dictionary.
del new_attrs[attr_name]
# We create the class as normal, except we use our new attributes.
return type.__new__(klass, name, bases, new_attrs)
# This is a class decorator that actually applies the above metaclass.
def parametrize_class(klass):
return ParametrizingMetaclass(klass.__name__,
klass.__bases__,
klass.__dict__)

View File

@@ -0,0 +1,5 @@
------WebKitFormBoundaryTkr3kCBQlBe1nrhc
Content-
isposition: form-data; name="field"
This is a test.

View File

@@ -0,0 +1,3 @@
boundary: ----WebKitFormBoundaryTkr3kCBQlBe1nrhc
expected:
error: 51

View File

@@ -0,0 +1,5 @@
------WebKitFormBoundaryTkr3kCBQlBe1nrhc
Content-Disposition: form-data; n
me="field"
This is a test.

View File

@@ -0,0 +1,3 @@
boundary: ----WebKitFormBoundaryTkr3kCBQlBe1nrhc
expected:
error: 76

View File

@@ -0,0 +1,13 @@
----boundary
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
--boundari
--boundaryq--boundary
q--boundarq
--bounaryd--
--notbound--
--mismatch
--mismatch--
--boundary-Q
--boundary

View File

@@ -0,0 +1,8 @@
boundary: --boundary
expected:
- name: file
type: file
file_name: test.txt
data: !!binary |
LS1ib3VuZGFyaQ0KLS1ib3VuZGFyeXEtLWJvdW5kYXJ5DXEtLWJvdW5kYXJxDQotLWJvdW5hcnlkLS0NCi0tbm90Ym91bmQtLQ0KLS1taXNtYXRjaA0KLS1taXNtYXRjaC0tDQotLWJvdW5kYXJ5LVENCi0tYm91bmRhcnkNUS0tYm91bmRhcnlR

View File

@@ -0,0 +1,6 @@
----boundary
Content-Disposition: form-data; name="field"
QQQQQQQQQQQQQQQQQQQQ
----boundaryQQQQQQQQQQQQQQQQQQQQ
----boundary--

View File

@@ -0,0 +1,8 @@
boundary: --boundary
expected:
- name: field
type: field
data: !!binary |
UVFRUVFRUVFRUVFRUVFRUVFRUVENCi0tLS1ib3VuZGFyeVFRUVFRUVFRUVFRUVFRUVFRUVFR

View File

@@ -0,0 +1,6 @@
----boundary
Content-Disposition: form-data; name="field"
QQQQQQQQQQQQQQQQQQQQ
----boundary
QQQQQQQQQQQQQQQQQQQQ

View File

@@ -0,0 +1,8 @@
boundary: --boundary
expected:
- name: field
type: field
data: !!binary |
UVFRUVFRUVFRUVFRUVFRUVFRUVENCi0tLS1ib3VuZGFyeQ1RUVFRUVFRUVFRUVFRUVFRUVFRUQ==

View File

@@ -0,0 +1,6 @@
----boundary
Content-Disposition: form-data; name="field"
QQQQQQQQQQQQQQQQQQQQ
----boundary-QQQQQQQQQQQQQQQQQQQQ
----boundary--

View File

@@ -0,0 +1,8 @@
boundary: --boundary
expected:
- name: field
type: field
data: !!binary |
UVFRUVFRUVFRUVFRUVFRUVFRUVENCi0tLS1ib3VuZGFyeS1RUVFRUVFRUVFRUVFRUVFRUVFRUQ==

View File

@@ -0,0 +1,4 @@
------WebKitFormBoundaryTkr3kCBQlBe1nrhc
Content-Disposition: form-data; name="field"
QThis is a test.

View File

@@ -0,0 +1,3 @@
boundary: ----WebKitFormBoundaryTkr3kCBQlBe1nrhc
expected:
error: 89

View File

@@ -0,0 +1,5 @@
------WebKitFormBoundaryTkr3kCBQlBe1nrhc
Content-999position: form-data; name="field"
This is a test.
------WebKitFormBoundaryTkr3kCBQlBe1nrhc--

View File

@@ -0,0 +1,3 @@
boundary: ----WebKitFormBoundaryTkr3kCBQlBe1nrhc
expected:
error: 50

View File

@@ -0,0 +1,5 @@
------WebQitFormBoundaryTkr3kCBQlBe1nrhc
Content-Disposition: form-data; name="field"
This is a test.
------WebKitFormBoundaryTkr3kCBQlBe1nrhc--

View File

@@ -0,0 +1,3 @@
boundary: ----WebKitFormBoundaryTkr3kCBQlBe1nrhc
expected:
error: 9

View File

@@ -0,0 +1,7 @@
----boundary
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
Content-Transfer-Encoding: base64
VGVzdCAxMjM=
----boundary--

View File

@@ -0,0 +1,7 @@
boundary: --boundary
expected:
- name: file
type: file
file_name: test.txt
data: !!binary |
VGVzdCAxMjM=

View File

@@ -0,0 +1,5 @@
------WebKitFormBoundaryTkr3kCBQlBe1nrhc
: form-data; name="field"
This is a test.
------WebKitFormBoundaryTkr3kCBQlBe1nrhc--

View File

@@ -0,0 +1,3 @@
boundary: ----WebKitFormBoundaryTkr3kCBQlBe1nrhc
expected:
error: 42

View File

@@ -0,0 +1,9 @@
------WebKitFormBoundaryTkr3kCBQlBe1nrhc
Content-Disposition: form-data; name="field1"
field1
------WebKitFormBoundaryTkr3kCBQlBe1nrhc
Content-Disposition: form-data; name="field2"
field2
------WebKitFormBoundaryTkr3kCBQlBe1nrhc--

View File

@@ -0,0 +1,10 @@
boundary: ----WebKitFormBoundaryTkr3kCBQlBe1nrhc
expected:
- name: field1
type: field
data: !!binary |
ZmllbGQx
- name: field2
type: field
data: !!binary |
ZmllbGQy

View File

@@ -0,0 +1,11 @@
------WebKitFormBoundarygbACTUR58IyeurVf
Content-Disposition: form-data; name="file1"; filename="test1.txt"
Content-Type: text/plain
Test file #1
------WebKitFormBoundarygbACTUR58IyeurVf
Content-Disposition: form-data; name="file2"; filename="test2.txt"
Content-Type: text/plain
Test file #2
------WebKitFormBoundarygbACTUR58IyeurVf--

View File

@@ -0,0 +1,13 @@
boundary: ----WebKitFormBoundarygbACTUR58IyeurVf
expected:
- name: file1
type: file
file_name: test1.txt
data: !!binary |
VGVzdCBmaWxlICMx
- name: file2
type: file
file_name: test2.txt
data: !!binary |
VGVzdCBmaWxlICMy

View File

@@ -0,0 +1,7 @@
----boundary
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable
foo=3Dbar
----boundary--

View File

@@ -0,0 +1,7 @@
boundary: --boundary
expected:
- name: file
type: file
file_name: test.txt
data: !!binary |
Zm9vPWJhcg==

View File

@@ -0,0 +1,5 @@
------WebKitFormBoundaryTkr3kCBQlBe1nrhc
Content-Disposition: form-data; name="field"
This is a test.
------WebKitFormBoundaryTkr3kCBQlBe1nrhc--

View File

@@ -0,0 +1,6 @@
boundary: ----WebKitFormBoundaryTkr3kCBQlBe1nrhc
expected:
- name: field
type: field
data: !!binary |
VGhpcyBpcyBhIHRlc3Qu

View File

@@ -0,0 +1,5 @@
--boundary
Content-Disposition: form-data; name="field"
0123456789ABCDEFGHIJ0123456789ABCDEFGHIJ
--boundary--

View File

@@ -0,0 +1,6 @@
boundary: --boundary
expected:
- name: field
type: field
data: !!binary |
MDEyMzQ1Njc4OUFCQ0RFRkdISUowMTIzNDU2Nzg5QUJDREVGR0hJSg==

View File

@@ -0,0 +1,5 @@
------WebKitFormBoundaryTkr3kCBQlBe1nrhc
Content-Disposition: form-data; name="field"
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
------WebKitFormBoundaryTkr3kCBQlBe1nrhc--

View File

@@ -0,0 +1,6 @@
boundary: ----WebKitFormBoundaryTkr3kCBQlBe1nrhc
expected:
- name: field
type: field
data: !!binary |
cXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXE=

View File

@@ -0,0 +1,10 @@
--boundary
Content-Disposition: form-data; name="field"
test1
--boundary
Content-Disposition: form-data; name="file"; filename="file.txt"
Content-Type: text/plain
test2
--boundary--

View File

@@ -0,0 +1,13 @@
boundary: boundary
expected:
- name: field
type: field
data: !!binary |
dGVzdDE=
- name: file
type: file
file_name: file.txt
data: !!binary |
dGVzdDI=

View File

@@ -0,0 +1,7 @@
------WebKitFormBoundaryTkr3kCBQlBe1nrhc
Content-Disposition: form-data; name="field"
This is a test.
------WebKitFormBoundaryTkr3kCBQlBe1nrhc--

View File

@@ -0,0 +1,6 @@
boundary: ----WebKitFormBoundaryTkr3kCBQlBe1nrhc
expected:
- name: field
type: field
data: !!binary |
VGhpcyBpcyBhIHRlc3Qu

View File

@@ -0,0 +1,6 @@
------WebKitFormBoundary5BZGOJCWtXGYC9HW
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
This is a test file.
------WebKitFormBoundary5BZGOJCWtXGYC9HW--

View File

@@ -0,0 +1,8 @@
boundary: ----WebKitFormBoundary5BZGOJCWtXGYC9HW
expected:
- name: file
type: file
file_name: test.txt
data: !!binary |
VGhpcyBpcyBhIHRlc3QgZmlsZS4=

View File

@@ -0,0 +1,6 @@
------WebKitFormBoundaryI9SCEFp2lpx5DR2K
Content-Disposition: form-data; name="file"; filename="???.txt"
Content-Type: text/plain
これはテストです。
------WebKitFormBoundaryI9SCEFp2lpx5DR2K--

View File

@@ -0,0 +1,8 @@
boundary: ----WebKitFormBoundaryI9SCEFp2lpx5DR2K
expected:
- name: file
type: file
file_name: ???.txt
data: !!binary |
44GT44KM44Gv44OG44K544OI44Gn44GZ44CC

File diff suppressed because it is too large Load Diff