u-toolkit 0.1.2__tar.gz → 0.1.4__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.
Files changed (41) hide show
  1. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/PKG-INFO +1 -1
  2. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/pyproject.toml +1 -1
  3. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/fastapi/cbv.py +27 -8
  4. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/tests/fastapi/test_cbv.py +14 -0
  5. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/uv.lock +53 -5
  6. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/.github/workflows/publish.yml +0 -0
  7. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/.gitignore +0 -0
  8. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/README.md +0 -0
  9. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/__init__.py +0 -0
  10. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/alias_generators.py +0 -0
  11. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/datetime.py +0 -0
  12. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/decorators.py +0 -0
  13. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/enum.py +0 -0
  14. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/fastapi/__init__.py +0 -0
  15. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/fastapi/config.py +0 -0
  16. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/fastapi/exception.py +0 -0
  17. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/fastapi/helpers.py +0 -0
  18. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/fastapi/lifespan.py +0 -0
  19. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/fastapi/pagination.py +0 -0
  20. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/fastapi/responses.py +0 -0
  21. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/function.py +0 -0
  22. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/helpers.py +0 -0
  23. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/logger.py +0 -0
  24. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/merge.py +0 -0
  25. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/object.py +0 -0
  26. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/path.py +0 -0
  27. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/pydantic/__init__.py +0 -0
  28. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/pydantic/fields.py +0 -0
  29. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/pydantic/models.py +0 -0
  30. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/pydantic/type_vars.py +0 -0
  31. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/signature.py +0 -0
  32. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/sqlalchemy/__init__.py +0 -0
  33. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/sqlalchemy/fields.py +0 -0
  34. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/sqlalchemy/function.py +0 -0
  35. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/sqlalchemy/orm/__init__.py +0 -0
  36. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/sqlalchemy/orm/fields.py +0 -0
  37. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/sqlalchemy/orm/models.py +0 -0
  38. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/sqlalchemy/table_info.py +0 -0
  39. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/src/u_toolkit/sqlalchemy/type_vars.py +0 -0
  40. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/tests/__init__.py +0 -0
  41. {u_toolkit-0.1.2 → u_toolkit-0.1.4}/tests/fastapi/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: u-toolkit
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: pydantic>=2.11.3
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "u-toolkit"
3
- version = "0.1.2"
3
+ version = "0.1.4"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -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) for method in Methods
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(name, "").replace("__", "/")
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,
@@ -299,6 +306,13 @@ class CBV:
299
306
 
300
307
  update_parameters(collect_cls_dependencies, *parameters)
301
308
 
309
+ def new_fn(method_name, kwargs):
310
+ instance = self._build_cls(cls)
311
+ dependencies = kwargs.pop(collect_cls_dependencies.__name__)
312
+ for dep_name, dep_value in dependencies.items():
313
+ setattr(instance, dep_name, dep_value)
314
+ return getattr(instance, method_name)
315
+
302
316
  def decorator(method: Callable):
303
317
  method_name = method.__name__
304
318
 
@@ -314,13 +328,18 @@ class CBV:
314
328
 
315
329
  update_parameters(sign_cls_fn, *(parameters[1:]))
316
330
 
331
+ if inspect.iscoroutinefunction(method):
332
+
333
+ @wraps(sign_cls_fn)
334
+ async def awrapper(*args, **kwargs):
335
+ fn = new_fn(method_name, kwargs)
336
+ return await fn(*args, **kwargs)
337
+
338
+ return awrapper
339
+
317
340
  @wraps(sign_cls_fn)
318
341
  def wrapper(*args, **kwargs):
319
- instance = self._build_cls(cls)
320
- dependencies = kwargs.pop(collect_cls_dependencies.__name__)
321
- for dep_name, dep_value in dependencies.items():
322
- setattr(instance, dep_name, dep_value)
323
- fn = getattr(instance, method_name)
342
+ fn = new_fn(method_name, kwargs)
324
343
  return fn(*args, **kwargs)
325
344
 
326
345
  return wrapper
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  from typing import Annotated, cast
2
3
 
3
4
  import sqlalchemy as sa
@@ -56,6 +57,16 @@ class R:
56
57
  def get(self):
57
58
  return self.value, self.value2, self.value3
58
59
 
60
+ def get__wtf____(self):
61
+ pass
62
+
63
+ @cbv.info(path="/lalala")
64
+ def get_custom(self): ...
65
+
66
+ async def get_async_value(self):
67
+ await asyncio.sleep(0.001)
68
+ return 1
69
+
59
70
  @cbv.info(status=status.HTTP_201_CREATED)
60
71
  def post(self):
61
72
  record = self.db_dep.execute(sa.text(f"select '{RESULT}'")).one()
@@ -79,6 +90,9 @@ client = TestClient(app)
79
90
 
80
91
  def test_cbv():
81
92
  assert client.get("/r").json() == [dep1_value, dep2_value, dep3_value]
93
+ assert client.get("/r/_wtf//").is_success
94
+ assert client.get("/lalala").is_success
95
+ assert client.get("/r/async_value").json() == 1
82
96
 
83
97
  post_resp = client.post("/r")
84
98
  assert post_resp.status_code == status.HTTP_201_CREATED
@@ -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.0"
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