u-toolkit 0.1.1__tar.gz → 0.1.2__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.2}/PKG-INFO +2 -1
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/pyproject.toml +4 -4
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/decorators.py +2 -1
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/fastapi/cbv.py +11 -6
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/signature.py +3 -4
- u_toolkit-0.1.2/tests/__init__.py +0 -0
- u_toolkit-0.1.2/tests/fastapi/__init__.py +0 -0
- u_toolkit-0.1.2/tests/fastapi/test_cbv.py +94 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/.github/workflows/publish.yml +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/.gitignore +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/README.md +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/__init__.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/alias_generators.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/datetime.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/enum.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/fastapi/__init__.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/fastapi/config.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/fastapi/exception.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/fastapi/helpers.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/fastapi/lifespan.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/fastapi/pagination.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/fastapi/responses.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/function.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/helpers.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/logger.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/merge.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/object.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/path.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/pydantic/__init__.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/pydantic/fields.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/pydantic/models.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/pydantic/type_vars.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/sqlalchemy/__init__.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/sqlalchemy/fields.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/sqlalchemy/function.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/sqlalchemy/orm/__init__.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/sqlalchemy/orm/fields.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/sqlalchemy/orm/models.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/sqlalchemy/table_info.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/src/u_toolkit/sqlalchemy/type_vars.py +0 -0
- {u_toolkit-0.1.1 → u_toolkit-0.1.2}/uv.lock +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.2
|
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.2"
|
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):
|
@@ -296,26 +296,31 @@ class CBV:
|
|
296
296
|
)
|
297
297
|
for name, dep in iter_dependencies(cls)
|
298
298
|
]
|
299
|
+
|
299
300
|
update_parameters(collect_cls_dependencies, *parameters)
|
300
301
|
|
301
302
|
def decorator(method: Callable):
|
302
|
-
|
303
|
-
|
303
|
+
method_name = method.__name__
|
304
|
+
|
305
|
+
cls_fn = getattr(cls, method_name)
|
306
|
+
sign_cls_fn = partial(cls_fn)
|
307
|
+
update_wrapper(sign_cls_fn, cls_fn)
|
304
308
|
|
305
309
|
parameters, *_ = with_parameter(
|
306
|
-
|
310
|
+
sign_cls_fn,
|
307
311
|
name=collect_cls_dependencies.__name__,
|
308
312
|
default=Depends(collect_cls_dependencies),
|
309
313
|
)
|
310
|
-
update_parameters(sign_fn, *parameters)
|
311
314
|
|
312
|
-
|
315
|
+
update_parameters(sign_cls_fn, *(parameters[1:]))
|
316
|
+
|
317
|
+
@wraps(sign_cls_fn)
|
313
318
|
def wrapper(*args, **kwargs):
|
314
319
|
instance = self._build_cls(cls)
|
315
320
|
dependencies = kwargs.pop(collect_cls_dependencies.__name__)
|
316
321
|
for dep_name, dep_value in dependencies.items():
|
317
322
|
setattr(instance, dep_name, dep_value)
|
318
|
-
fn = getattr(instance,
|
323
|
+
fn = getattr(instance, method_name)
|
319
324
|
return fn(*args, **kwargs)
|
320
325
|
|
321
326
|
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,94 @@
|
|
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
|
+
|
65
|
+
@cbv
|
66
|
+
class _NoPath:
|
67
|
+
value = Depends(dep1)
|
68
|
+
|
69
|
+
def post(self, data: Annotated[OAuth2PasswordRequestForm, Depends()]):
|
70
|
+
return data.username
|
71
|
+
|
72
|
+
|
73
|
+
app = FastAPI()
|
74
|
+
|
75
|
+
|
76
|
+
app.include_router(cbv.router)
|
77
|
+
client = TestClient(app)
|
78
|
+
|
79
|
+
|
80
|
+
def test_cbv():
|
81
|
+
assert client.get("/r").json() == [dep1_value, dep2_value, dep3_value]
|
82
|
+
|
83
|
+
post_resp = client.post("/r")
|
84
|
+
assert post_resp.status_code == status.HTTP_201_CREATED
|
85
|
+
assert post_resp.json() == RESULT
|
86
|
+
|
87
|
+
value = "example"
|
88
|
+
assert (
|
89
|
+
client.post(
|
90
|
+
"/",
|
91
|
+
data={"username": value, "password": value},
|
92
|
+
).json()
|
93
|
+
== value
|
94
|
+
)
|
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
|
File without changes
|