fastapi-extra 0.2.5__tar.gz → 0.3.0__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.
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/PKG-INFO +3 -3
- fastapi_extra-0.3.0/fastapi_extra/__init__.py +17 -0
- fastapi_extra-0.3.0/fastapi_extra/_patch.py +33 -0
- fastapi_extra-0.3.0/fastapi_extra/native/urlparse.pyx +50 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/response.py +15 -1
- fastapi_extra-0.3.0/fastapi_extra/urlparse.pyi +11 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra.egg-info/PKG-INFO +3 -3
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra.egg-info/SOURCES.txt +5 -1
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra.egg-info/requires.txt +2 -2
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/pyproject.toml +4 -3
- fastapi_extra-0.2.5/fastapi_extra/__init__.py +0 -13
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/LICENSE +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/README.rst +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/cache/__init__.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/cache/redis.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/cursor.pyi +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/database/__init__.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/database/model.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/database/service.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/database/session.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/dependency.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/form.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/native/cursor.pyx +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/native/routing.pyx +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/py.typed +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/routing.pyi +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/settings.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/types.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra/utils.py +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra.egg-info/dependency_links.txt +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/fastapi_extra.egg-info/top_level.txt +0 -0
- {fastapi_extra-0.2.5 → fastapi_extra-0.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-extra
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: extra package for fastapi.
|
|
5
5
|
Author-email: Ziyan Yin <408856732@qq.com>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -18,9 +18,9 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
18
18
|
Requires-Python: >=3.12
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: fastapi<0.
|
|
21
|
+
Requires-Dist: fastapi<0.129.0,>=0.128.0
|
|
22
22
|
Requires-Dist: httpx<0.29.0,>=0.28.0
|
|
23
|
-
Requires-Dist: pydantic-settings>=2.
|
|
23
|
+
Requires-Dist: pydantic-settings>=2.12.0
|
|
24
24
|
Requires-Dist: sqlmodel>=0.0.22
|
|
25
25
|
Provides-Extra: redis
|
|
26
26
|
Requires-Dist: redis; extra == "redis"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
__version__ = "0.3.0"
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from fastapi import FastAPI
|
|
5
|
+
from fastapi import routing as origin_routing
|
|
6
|
+
from fastapi.dependencies import utils as origin_utils
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def setup(app: FastAPI) -> None:
|
|
10
|
+
try:
|
|
11
|
+
from fastapi_extra import _patch
|
|
12
|
+
|
|
13
|
+
_patch.install_routes(app)
|
|
14
|
+
origin_routing.solve_dependencies.__globals__['is_sequence_field'] = _patch.is_sequence_field # type: ignore
|
|
15
|
+
origin_utils.QueryParams.__init__ = _patch.query_params_init # type: ignore
|
|
16
|
+
except ImportError: # pragma: nocover
|
|
17
|
+
pass
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
__author__ = "ziyan.yin"
|
|
2
|
+
__date__ = "2026-01-13"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from fastapi import FastAPI
|
|
6
|
+
from fastapi._compat import v2
|
|
7
|
+
from starlette import datastructures
|
|
8
|
+
|
|
9
|
+
from fastapi_extra import routing
|
|
10
|
+
from fastapi_extra.urlparse import parse_qsl
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def install_routes(app: FastAPI) -> None:
|
|
14
|
+
routing.install(app)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def is_sequence_field(field: v2.ModelField) -> bool:
|
|
18
|
+
if not hasattr(field, "_is_sequence"):
|
|
19
|
+
setattr(field, "_is_sequence", v2.is_sequence_field(field))
|
|
20
|
+
return getattr(field, "_is_sequence")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def query_params_init(obj: datastructures.QueryParams, *args, **kwargs) -> None:
|
|
24
|
+
value = args[0] if args else []
|
|
25
|
+
|
|
26
|
+
if isinstance(value, bytes):
|
|
27
|
+
super(datastructures.QueryParams, obj).__init__(parse_qsl(value, keep_blank_values=True), **kwargs)
|
|
28
|
+
elif isinstance(value, str):
|
|
29
|
+
super(datastructures.QueryParams, obj).__init__(parse_qsl(value.encode("latin-1"), keep_blank_values=True), **kwargs)
|
|
30
|
+
else:
|
|
31
|
+
super(datastructures.QueryParams, obj).__init__(*args, **kwargs) # type: ignore[arg-type]
|
|
32
|
+
obj._list = [(str(k), str(v)) for k, v in obj._list]
|
|
33
|
+
obj._dict = {str(k): str(v) for k, v in obj._dict.items()}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
__author__ = "ziyan.yin"
|
|
2
|
+
__describe__ = ""
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from libc.stdlib cimport strtol
|
|
6
|
+
from libc.string cimport memmove, strlen
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
cdef inline size_t _unquote(char* c_string, bint change_plus):
|
|
10
|
+
cdef:
|
|
11
|
+
int i = 0
|
|
12
|
+
char[2] quote
|
|
13
|
+
size_t n = strlen(c_string)
|
|
14
|
+
|
|
15
|
+
while i < n:
|
|
16
|
+
if c_string[i] == '+' and change_plus:
|
|
17
|
+
c_string[i] = ' '
|
|
18
|
+
elif c_string[i] == '%':
|
|
19
|
+
quote[0] = c_string[i + 1]
|
|
20
|
+
quote[1] = c_string[i + 2]
|
|
21
|
+
c_string[i] = strtol(quote, NULL, 16)
|
|
22
|
+
memmove(c_string + i + 1, c_string + i + 3, n - i - 2)
|
|
23
|
+
n -= 2
|
|
24
|
+
i += 1
|
|
25
|
+
return n
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def unquote(val: bytes, encoding: str = "utf-8") -> str:
|
|
29
|
+
return val[:_unquote(val, 0)].decode(encoding)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def unquote_plus(val: bytes, encoding: str = "utf-8") -> str:
|
|
33
|
+
return val[:_unquote(val, 1)].decode(encoding)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def parse_qsl(qs: bytes, keep_blank_values: bool = False) -> list[tuple[str, str]]:
|
|
37
|
+
query_args = qs.split(b'&') if qs else []
|
|
38
|
+
r = []
|
|
39
|
+
for name_value in query_args:
|
|
40
|
+
if not name_value:
|
|
41
|
+
continue
|
|
42
|
+
nv = name_value.split(b'=')
|
|
43
|
+
if len(nv) < 2:
|
|
44
|
+
if not keep_blank_values:
|
|
45
|
+
continue
|
|
46
|
+
nv.append(b'')
|
|
47
|
+
name = unquote_plus(nv[0])
|
|
48
|
+
value = unquote_plus(nv[1])
|
|
49
|
+
r.append((name, value))
|
|
50
|
+
return r
|
|
@@ -3,7 +3,7 @@ __date__ = "2024-12-24"
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
from enum import Enum
|
|
6
|
-
from typing import TYPE_CHECKING, Generic
|
|
6
|
+
from typing import TYPE_CHECKING, Generic, Mapping
|
|
7
7
|
|
|
8
8
|
from fastapi.responses import JSONResponse
|
|
9
9
|
from pydantic import BaseModel, Field
|
|
@@ -220,6 +220,20 @@ class APIResponse(JSONResponse):
|
|
|
220
220
|
exclude_none=False,
|
|
221
221
|
exclude_unset=False,
|
|
222
222
|
)
|
|
223
|
+
|
|
224
|
+
def init_headers(self, headers: Mapping[str, str] | None = None) -> None:
|
|
225
|
+
self.raw_headers = [
|
|
226
|
+
(b"content-length", str(len(self.body)).encode("latin-1")),
|
|
227
|
+
(b"content-type", b"application/json; charset=utf-8"),
|
|
228
|
+
]
|
|
229
|
+
if headers:
|
|
230
|
+
raw_headers = [
|
|
231
|
+
(k.lower().encode("latin-1"), v.encode("latin-1"))
|
|
232
|
+
for k, v in headers.items() if k not in ("content-length", "content-type")
|
|
233
|
+
]
|
|
234
|
+
self.raw_headers.extend(raw_headers)
|
|
235
|
+
|
|
236
|
+
|
|
223
237
|
|
|
224
238
|
|
|
225
239
|
class APIError(Exception):
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
__author__ = "ziyan.yin"
|
|
2
|
+
__describe__ = ""
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def unquote(val: bytes, encoding: str = "utf-8") -> str: ...
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def unquote_plus(val: bytes, encoding: str = "utf-8") -> str: ...
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def parse_qsl(qs: bytes, keep_blank_values: bool = False) -> list[tuple[str, str]]: ...
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-extra
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: extra package for fastapi.
|
|
5
5
|
Author-email: Ziyan Yin <408856732@qq.com>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -18,9 +18,9 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
18
18
|
Requires-Python: >=3.12
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
20
20
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: fastapi<0.
|
|
21
|
+
Requires-Dist: fastapi<0.129.0,>=0.128.0
|
|
22
22
|
Requires-Dist: httpx<0.29.0,>=0.28.0
|
|
23
|
-
Requires-Dist: pydantic-settings>=2.
|
|
23
|
+
Requires-Dist: pydantic-settings>=2.12.0
|
|
24
24
|
Requires-Dist: sqlmodel>=0.0.22
|
|
25
25
|
Provides-Extra: redis
|
|
26
26
|
Requires-Dist: redis; extra == "redis"
|
|
@@ -2,6 +2,7 @@ LICENSE
|
|
|
2
2
|
README.rst
|
|
3
3
|
pyproject.toml
|
|
4
4
|
fastapi_extra/__init__.py
|
|
5
|
+
fastapi_extra/_patch.py
|
|
5
6
|
fastapi_extra/cursor.pyi
|
|
6
7
|
fastapi_extra/dependency.py
|
|
7
8
|
fastapi_extra/form.py
|
|
@@ -10,6 +11,7 @@ fastapi_extra/response.py
|
|
|
10
11
|
fastapi_extra/routing.pyi
|
|
11
12
|
fastapi_extra/settings.py
|
|
12
13
|
fastapi_extra/types.py
|
|
14
|
+
fastapi_extra/urlparse.pyi
|
|
13
15
|
fastapi_extra/utils.py
|
|
14
16
|
fastapi_extra.egg-info/PKG-INFO
|
|
15
17
|
fastapi_extra.egg-info/SOURCES.txt
|
|
@@ -18,6 +20,7 @@ fastapi_extra.egg-info/requires.txt
|
|
|
18
20
|
fastapi_extra.egg-info/top_level.txt
|
|
19
21
|
fastapi_extra/native/cursor.pyx
|
|
20
22
|
fastapi_extra/native/routing.pyx
|
|
23
|
+
fastapi_extra/native/urlparse.pyx
|
|
21
24
|
fastapi_extra/cache/__init__.py
|
|
22
25
|
fastapi_extra/cache/redis.py
|
|
23
26
|
fastapi_extra/database/__init__.py
|
|
@@ -25,4 +28,5 @@ fastapi_extra/database/model.py
|
|
|
25
28
|
fastapi_extra/database/service.py
|
|
26
29
|
fastapi_extra/database/session.py
|
|
27
30
|
fastapi_extra/native/cursor.pyx
|
|
28
|
-
fastapi_extra/native/routing.pyx
|
|
31
|
+
fastapi_extra/native/routing.pyx
|
|
32
|
+
fastapi_extra/native/urlparse.pyx
|
|
@@ -30,9 +30,9 @@ classifiers = [
|
|
|
30
30
|
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
31
31
|
]
|
|
32
32
|
dependencies = [
|
|
33
|
-
"fastapi>=0.
|
|
33
|
+
"fastapi>=0.128.0,<0.129.0",
|
|
34
34
|
"httpx>=0.28.0,<0.29.0",
|
|
35
|
-
"pydantic-settings>=2.
|
|
35
|
+
"pydantic-settings>=2.12.0",
|
|
36
36
|
"sqlmodel>=0.0.22",
|
|
37
37
|
]
|
|
38
38
|
|
|
@@ -47,7 +47,8 @@ aiomysql = ["aiomysql"]
|
|
|
47
47
|
packages = ["fastapi_extra", "fastapi_extra.database", "fastapi_extra.cache"]
|
|
48
48
|
ext-modules = [
|
|
49
49
|
{ name = "fastapi_extra.cursor", sources = ["fastapi_extra/native/cursor.pyx"] },
|
|
50
|
-
{ name = "fastapi_extra.routing", sources = ["fastapi_extra/native/routing.pyx"] }
|
|
50
|
+
{ name = "fastapi_extra.routing", sources = ["fastapi_extra/native/routing.pyx"] },
|
|
51
|
+
{ name = "fastapi_extra.urlparse", sources = ["fastapi_extra/native/urlparse.pyx"] }
|
|
51
52
|
]
|
|
52
53
|
|
|
53
54
|
[tool.setuptools.dynamic]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|