u-toolkit 0.1.1__tar.gz → 0.1.3__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.
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/PKG-INFO +2 -1
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/pyproject.toml +4 -4
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/decorators.py +2 -1
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/fastapi/cbv.py +21 -9
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/signature.py +3 -4
- u_toolkit-0.1.3/tests/__init__.py +0 -0
- u_toolkit-0.1.3/tests/fastapi/__init__.py +0 -0
- u_toolkit-0.1.3/tests/fastapi/test_cbv.py +101 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/uv.lock +53 -5
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/.github/workflows/publish.yml +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/.gitignore +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/README.md +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/__init__.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/alias_generators.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/datetime.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/enum.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/fastapi/__init__.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/fastapi/config.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/fastapi/exception.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/fastapi/helpers.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/fastapi/lifespan.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/fastapi/pagination.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/fastapi/responses.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/function.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/helpers.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/logger.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/merge.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/object.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/path.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/pydantic/__init__.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/pydantic/fields.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/pydantic/models.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/pydantic/type_vars.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/sqlalchemy/__init__.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/sqlalchemy/fields.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/sqlalchemy/function.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/sqlalchemy/orm/__init__.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/sqlalchemy/orm/fields.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/sqlalchemy/orm/models.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/sqlalchemy/table_info.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.3}/src/u_toolkit/sqlalchemy/type_vars.py +0 -0
@@ -1,10 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: u-toolkit
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.3
|
4
4
|
Summary: Add your description here
|
5
5
|
Requires-Python: >=3.11
|
6
6
|
Requires-Dist: pydantic>=2.11.3
|
7
7
|
Provides-Extra: fastapi
|
8
|
+
Requires-Dist: fastapi>=0.115.12; extra == 'fastapi'
|
8
9
|
Requires-Dist: pydantic-settings>=2.9.1; extra == 'fastapi'
|
9
10
|
Provides-Extra: sqlalchemy
|
10
11
|
Requires-Dist: sqlalchemy>=2.0.40; extra == 'sqlalchemy'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "u-toolkit"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.3"
|
4
4
|
description = "Add your description here"
|
5
5
|
readme = "README.md"
|
6
6
|
requires-python = ">=3.11"
|
@@ -16,6 +16,7 @@ sqlalchemy = [
|
|
16
16
|
"sqlalchemy>=2.0.40",
|
17
17
|
]
|
18
18
|
fastapi = [
|
19
|
+
"fastapi>=0.115.12",
|
19
20
|
"pydantic-settings>=2.9.1",
|
20
21
|
]
|
21
22
|
|
@@ -26,13 +27,12 @@ build-backend = "hatchling.build"
|
|
26
27
|
[dependency-groups]
|
27
28
|
dev = [
|
28
29
|
"devtools>=0.12.2",
|
30
|
+
"httpx>=0.28.1",
|
29
31
|
"pytest>=8.3.5",
|
32
|
+
"python-multipart>=0.0.20",
|
30
33
|
"ruff>=0.11.6",
|
31
34
|
"uvicorn>=0.34.2",
|
32
35
|
]
|
33
|
-
fastapi = [
|
34
|
-
"fastapi>=0.115.12",
|
35
|
-
]
|
36
36
|
|
37
37
|
|
38
38
|
|
@@ -27,7 +27,8 @@ class DefineMethodDecorator(Generic[_T, _FnT]):
|
|
27
27
|
self.register_method(DefineMethodParams(owner_class, name, self.fn))
|
28
28
|
|
29
29
|
def __get__(self, instance: _T, owner_class: type[_T]):
|
30
|
-
|
30
|
+
parameters = list_parameters(self.fn)[1:]
|
31
|
+
update_parameters(self.fn, *parameters)
|
31
32
|
|
32
33
|
@wraps(self.fn)
|
33
34
|
def wrapper(*args, **kwargs):
|
@@ -24,7 +24,8 @@ class EndpointsClassInterface(Protocol):
|
|
24
24
|
deprecated: bool | None = None
|
25
25
|
|
26
26
|
@classmethod
|
27
|
-
def build_self(cls) -> Self:
|
27
|
+
def build_self(cls) -> Self:
|
28
|
+
return cls()
|
28
29
|
|
29
30
|
|
30
31
|
_T = TypeVar("_T")
|
@@ -68,7 +69,8 @@ class Methods(StrEnum):
|
|
68
69
|
|
69
70
|
|
70
71
|
METHOD_PATTERNS = {
|
71
|
-
method: re.compile(f"^{method}", re.IGNORECASE)
|
72
|
+
method: re.compile(f"^({method}_|{method})", re.IGNORECASE)
|
73
|
+
for method in Methods
|
72
74
|
}
|
73
75
|
|
74
76
|
_FnName = str
|
@@ -107,7 +109,7 @@ def iter_endpoints(cls: type[_T]):
|
|
107
109
|
paths = [prefix]
|
108
110
|
|
109
111
|
if method := get_method(name):
|
110
|
-
path = method[1].sub(
|
112
|
+
path = method[1].sub("", name).replace("__", "/")
|
111
113
|
if path:
|
112
114
|
paths.append(path)
|
113
115
|
|
@@ -136,6 +138,7 @@ def iter_dependencies(cls: type[_T]):
|
|
136
138
|
|
137
139
|
|
138
140
|
_CBVEndpointParamName = Literal[
|
141
|
+
"path",
|
139
142
|
"tags",
|
140
143
|
"dependencies",
|
141
144
|
"responses",
|
@@ -197,6 +200,8 @@ class CBV:
|
|
197
200
|
method
|
198
201
|
]
|
199
202
|
|
203
|
+
path = self._state[cls][method_name].get("path") or path
|
204
|
+
|
200
205
|
return self.router.api_route(
|
201
206
|
path,
|
202
207
|
methods=endpoint_methods,
|
@@ -211,6 +216,7 @@ class CBV:
|
|
211
216
|
def info(
|
212
217
|
self,
|
213
218
|
*,
|
219
|
+
path: str | None = None,
|
214
220
|
methods: list[Methods | LiteralUpperMethods | LiteralLowerMethods]
|
215
221
|
| None = None,
|
216
222
|
tags: list[str | Enum] | None = None,
|
@@ -223,6 +229,7 @@ class CBV:
|
|
223
229
|
state = self._state
|
224
230
|
initial_state = self._initial_state
|
225
231
|
data: dict[_CBVEndpointParamName, Any] = {
|
232
|
+
"path": path,
|
226
233
|
"methods": methods,
|
227
234
|
"tags": tags,
|
228
235
|
"dependencies": dependencies,
|
@@ -296,26 +303,31 @@ class CBV:
|
|
296
303
|
)
|
297
304
|
for name, dep in iter_dependencies(cls)
|
298
305
|
]
|
306
|
+
|
299
307
|
update_parameters(collect_cls_dependencies, *parameters)
|
300
308
|
|
301
309
|
def decorator(method: Callable):
|
302
|
-
|
303
|
-
|
310
|
+
method_name = method.__name__
|
311
|
+
|
312
|
+
cls_fn = getattr(cls, method_name)
|
313
|
+
sign_cls_fn = partial(cls_fn)
|
314
|
+
update_wrapper(sign_cls_fn, cls_fn)
|
304
315
|
|
305
316
|
parameters, *_ = with_parameter(
|
306
|
-
|
317
|
+
sign_cls_fn,
|
307
318
|
name=collect_cls_dependencies.__name__,
|
308
319
|
default=Depends(collect_cls_dependencies),
|
309
320
|
)
|
310
|
-
update_parameters(sign_fn, *parameters)
|
311
321
|
|
312
|
-
|
322
|
+
update_parameters(sign_cls_fn, *(parameters[1:]))
|
323
|
+
|
324
|
+
@wraps(sign_cls_fn)
|
313
325
|
def wrapper(*args, **kwargs):
|
314
326
|
instance = self._build_cls(cls)
|
315
327
|
dependencies = kwargs.pop(collect_cls_dependencies.__name__)
|
316
328
|
for dep_name, dep_value in dependencies.items():
|
317
329
|
setattr(instance, dep_name, dep_value)
|
318
|
-
fn = getattr(instance,
|
330
|
+
fn = getattr(instance, method_name)
|
319
331
|
return fn(*args, **kwargs)
|
320
332
|
|
321
333
|
return wrapper
|
@@ -57,13 +57,12 @@ def update_signature(
|
|
57
57
|
return_annotation: type | None = None,
|
58
58
|
):
|
59
59
|
signature = inspect.signature(fn)
|
60
|
-
kwargs = {}
|
61
60
|
if parameters:
|
62
|
-
|
61
|
+
signature = signature.replace(parameters=parameters)
|
63
62
|
if return_annotation:
|
64
|
-
|
63
|
+
signature = signature.replace(return_annotation=return_annotation)
|
65
64
|
|
66
|
-
fn
|
65
|
+
setattr(fn, "__signature__", signature)
|
67
66
|
|
68
67
|
|
69
68
|
def update_parameters(fn: Callable, *parameters: inspect.Parameter):
|
File without changes
|
File without changes
|
@@ -0,0 +1,101 @@
|
|
1
|
+
from typing import Annotated, cast
|
2
|
+
|
3
|
+
import sqlalchemy as sa
|
4
|
+
from fastapi import Depends, FastAPI, status
|
5
|
+
from fastapi.security import OAuth2PasswordRequestForm
|
6
|
+
from fastapi.testclient import TestClient
|
7
|
+
|
8
|
+
from u_toolkit.fastapi.cbv import CBV
|
9
|
+
|
10
|
+
|
11
|
+
cbv = CBV()
|
12
|
+
|
13
|
+
|
14
|
+
def gen_value():
|
15
|
+
return id(object())
|
16
|
+
|
17
|
+
|
18
|
+
dep1_value = gen_value()
|
19
|
+
|
20
|
+
|
21
|
+
def dep1():
|
22
|
+
return dep1_value
|
23
|
+
|
24
|
+
|
25
|
+
dep2_value = gen_value()
|
26
|
+
|
27
|
+
|
28
|
+
def dep2():
|
29
|
+
return dep2_value
|
30
|
+
|
31
|
+
|
32
|
+
dep3_value = gen_value()
|
33
|
+
|
34
|
+
|
35
|
+
def dep3():
|
36
|
+
yield dep3_value
|
37
|
+
|
38
|
+
|
39
|
+
def db():
|
40
|
+
with sa.create_engine(
|
41
|
+
"sqlite+pysqlite:///:memory:", echo=True, future=True
|
42
|
+
).connect() as conn:
|
43
|
+
yield conn
|
44
|
+
|
45
|
+
|
46
|
+
RESULT = "hello world"
|
47
|
+
|
48
|
+
|
49
|
+
@cbv
|
50
|
+
class R:
|
51
|
+
value = Depends(dep1)
|
52
|
+
value2: Annotated[int, Depends(dep2)]
|
53
|
+
value3 = Depends(dep3)
|
54
|
+
db_dep = cast(sa.Connection, Depends(db))
|
55
|
+
|
56
|
+
def get(self):
|
57
|
+
return self.value, self.value2, self.value3
|
58
|
+
|
59
|
+
@cbv.info(status=status.HTTP_201_CREATED)
|
60
|
+
def post(self):
|
61
|
+
record = self.db_dep.execute(sa.text(f"select '{RESULT}'")).one()
|
62
|
+
return record[0]
|
63
|
+
|
64
|
+
def get__wtf____(self):
|
65
|
+
pass
|
66
|
+
|
67
|
+
@cbv.info(path="/lalala")
|
68
|
+
def get_custom(self): ...
|
69
|
+
|
70
|
+
|
71
|
+
@cbv
|
72
|
+
class _NoPath:
|
73
|
+
value = Depends(dep1)
|
74
|
+
|
75
|
+
def post(self, data: Annotated[OAuth2PasswordRequestForm, Depends()]):
|
76
|
+
return data.username
|
77
|
+
|
78
|
+
|
79
|
+
app = FastAPI()
|
80
|
+
|
81
|
+
|
82
|
+
app.include_router(cbv.router)
|
83
|
+
client = TestClient(app)
|
84
|
+
|
85
|
+
|
86
|
+
def test_cbv():
|
87
|
+
assert client.get("/r").json() == [dep1_value, dep2_value, dep3_value]
|
88
|
+
assert client.get("/_wtf____").is_success
|
89
|
+
|
90
|
+
post_resp = client.post("/r")
|
91
|
+
assert post_resp.status_code == status.HTTP_201_CREATED
|
92
|
+
assert post_resp.json() == RESULT
|
93
|
+
|
94
|
+
value = "example"
|
95
|
+
assert (
|
96
|
+
client.post(
|
97
|
+
"/",
|
98
|
+
data={"username": value, "password": value},
|
99
|
+
).json()
|
100
|
+
== value
|
101
|
+
)
|
@@ -37,6 +37,15 @@ wheels = [
|
|
37
37
|
{ url = "https://files.pythonhosted.org/packages/45/86/4736ac618d82a20d87d2f92ae19441ebc7ac9e7a581d7e58bbe79233b24a/asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", size = 27764 },
|
38
38
|
]
|
39
39
|
|
40
|
+
[[package]]
|
41
|
+
name = "certifi"
|
42
|
+
version = "2025.1.31"
|
43
|
+
source = { registry = "https://pypi.org/simple" }
|
44
|
+
sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 }
|
45
|
+
wheels = [
|
46
|
+
{ url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 },
|
47
|
+
]
|
48
|
+
|
40
49
|
[[package]]
|
41
50
|
name = "click"
|
42
51
|
version = "8.1.8"
|
@@ -147,6 +156,34 @@ wheels = [
|
|
147
156
|
{ url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
|
148
157
|
]
|
149
158
|
|
159
|
+
[[package]]
|
160
|
+
name = "httpcore"
|
161
|
+
version = "1.0.8"
|
162
|
+
source = { registry = "https://pypi.org/simple" }
|
163
|
+
dependencies = [
|
164
|
+
{ name = "certifi" },
|
165
|
+
{ name = "h11" },
|
166
|
+
]
|
167
|
+
sdist = { url = "https://files.pythonhosted.org/packages/9f/45/ad3e1b4d448f22c0cff4f5692f5ed0666658578e358b8d58a19846048059/httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad", size = 85385 }
|
168
|
+
wheels = [
|
169
|
+
{ url = "https://files.pythonhosted.org/packages/18/8d/f052b1e336bb2c1fc7ed1aaed898aa570c0b61a09707b108979d9fc6e308/httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be", size = 78732 },
|
170
|
+
]
|
171
|
+
|
172
|
+
[[package]]
|
173
|
+
name = "httpx"
|
174
|
+
version = "0.28.1"
|
175
|
+
source = { registry = "https://pypi.org/simple" }
|
176
|
+
dependencies = [
|
177
|
+
{ name = "anyio" },
|
178
|
+
{ name = "certifi" },
|
179
|
+
{ name = "httpcore" },
|
180
|
+
{ name = "idna" },
|
181
|
+
]
|
182
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 }
|
183
|
+
wheels = [
|
184
|
+
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 },
|
185
|
+
]
|
186
|
+
|
150
187
|
[[package]]
|
151
188
|
name = "idna"
|
152
189
|
version = "3.10"
|
@@ -310,6 +347,15 @@ wheels = [
|
|
310
347
|
{ url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256 },
|
311
348
|
]
|
312
349
|
|
350
|
+
[[package]]
|
351
|
+
name = "python-multipart"
|
352
|
+
version = "0.0.20"
|
353
|
+
source = { registry = "https://pypi.org/simple" }
|
354
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158 }
|
355
|
+
wheels = [
|
356
|
+
{ url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546 },
|
357
|
+
]
|
358
|
+
|
313
359
|
[[package]]
|
314
360
|
name = "ruff"
|
315
361
|
version = "0.11.6"
|
@@ -425,7 +471,7 @@ wheels = [
|
|
425
471
|
|
426
472
|
[[package]]
|
427
473
|
name = "u-toolkit"
|
428
|
-
version = "0.1.
|
474
|
+
version = "0.1.1"
|
429
475
|
source = { editable = "." }
|
430
476
|
dependencies = [
|
431
477
|
{ name = "pydantic" },
|
@@ -433,6 +479,7 @@ dependencies = [
|
|
433
479
|
|
434
480
|
[package.optional-dependencies]
|
435
481
|
fastapi = [
|
482
|
+
{ name = "fastapi" },
|
436
483
|
{ name = "pydantic-settings" },
|
437
484
|
]
|
438
485
|
sqlalchemy = [
|
@@ -442,16 +489,16 @@ sqlalchemy = [
|
|
442
489
|
[package.dev-dependencies]
|
443
490
|
dev = [
|
444
491
|
{ name = "devtools" },
|
492
|
+
{ name = "httpx" },
|
445
493
|
{ name = "pytest" },
|
494
|
+
{ name = "python-multipart" },
|
446
495
|
{ name = "ruff" },
|
447
496
|
{ name = "uvicorn" },
|
448
497
|
]
|
449
|
-
fastapi = [
|
450
|
-
{ name = "fastapi" },
|
451
|
-
]
|
452
498
|
|
453
499
|
[package.metadata]
|
454
500
|
requires-dist = [
|
501
|
+
{ name = "fastapi", marker = "extra == 'fastapi'", specifier = ">=0.115.12" },
|
455
502
|
{ name = "pydantic", specifier = ">=2.11.3" },
|
456
503
|
{ name = "pydantic-settings", marker = "extra == 'fastapi'", specifier = ">=2.9.1" },
|
457
504
|
{ name = "sqlalchemy", marker = "extra == 'sqlalchemy'", specifier = ">=2.0.40" },
|
@@ -461,11 +508,12 @@ provides-extras = ["sqlalchemy", "fastapi"]
|
|
461
508
|
[package.metadata.requires-dev]
|
462
509
|
dev = [
|
463
510
|
{ name = "devtools", specifier = ">=0.12.2" },
|
511
|
+
{ name = "httpx", specifier = ">=0.28.1" },
|
464
512
|
{ name = "pytest", specifier = ">=8.3.5" },
|
513
|
+
{ name = "python-multipart", specifier = ">=0.0.20" },
|
465
514
|
{ name = "ruff", specifier = ">=0.11.6" },
|
466
515
|
{ name = "uvicorn", specifier = ">=0.34.2" },
|
467
516
|
]
|
468
|
-
fastapi = [{ name = "fastapi", specifier = ">=0.115.12" }]
|
469
517
|
|
470
518
|
[[package]]
|
471
519
|
name = "uvicorn"
|
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
|
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
|