fastapi-extra 0.2.4__cp312-cp312-win_amd64.whl → 0.3.0__cp312-cp312-win_amd64.whl

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/__init__.py CHANGED
@@ -1,13 +1,17 @@
1
- __version__ = "0.2.4"
1
+ __version__ = "0.3.0"
2
2
 
3
3
 
4
4
  from fastapi import FastAPI
5
+ from fastapi import routing as origin_routing
6
+ from fastapi.dependencies import utils as origin_utils
5
7
 
6
8
 
7
9
  def setup(app: FastAPI) -> None:
8
10
  try:
9
- from fastapi_extra import routing as native_routing # type: ignore
11
+ from fastapi_extra import _patch
10
12
 
11
- native_routing.install(app)
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
12
16
  except ImportError: # pragma: nocover
13
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()}
@@ -3,6 +3,4 @@ __date__ = "2025-01-10"
3
3
 
4
4
  from .redis import RedisCli as Redis
5
5
 
6
- __all__ = [
7
- "Redis"
8
- ]
6
+ __all__ = ["Redis"]
@@ -30,18 +30,20 @@ class RedisPool(AbstractComponent):
30
30
 
31
31
  def __init__(self):
32
32
  self._pool: ConnectionPool | None = None
33
-
33
+
34
34
  @classmethod
35
35
  def setup(cls, **options) -> Self:
36
36
  redis = cls()
37
37
  redis._pool = ConnectionPool.from_url(
38
- cls.default_config.url,
39
- **cls.default_config.model_dump(exclude_defaults=True, exclude={"url", "connection_kwargs"}),
40
- **cls.default_config.connection_kwargs
41
- **options
38
+ str(cls.default_config.url),
39
+ **cls.default_config.model_dump(
40
+ exclude_defaults=True, exclude={"url", "connection_kwargs"}
41
+ ),
42
+ **cls.default_config.connection_kwargs,
43
+ **options,
42
44
  )
43
45
  return redis
44
-
46
+
45
47
  def get_client(self) -> Redis:
46
48
  return Redis(connection_pool=self._pool)
47
49
 
@@ -50,9 +52,8 @@ class RedisPool(AbstractComponent):
50
52
  await self._pool.aclose()
51
53
 
52
54
 
53
-
54
55
  async def get_redis(pool: RedisPool) -> AsyncGenerator[Redis, None]:
55
- async with RedisPool.get_client as client:
56
+ async with pool.get_client() as client:
56
57
  yield client
57
58
 
58
59
 
Binary file
fastapi_extra/cursor.pyi CHANGED
@@ -1,8 +1,8 @@
1
1
  __author__ = "ziyan.yin"
2
2
  __describe__ = ""
3
3
 
4
-
5
4
  class Cursor:
6
5
 
7
- def next_val(self) -> int:
8
- ...
6
+ def __init__(self, seed: int) -> None: ...
7
+
8
+ def next_val(self) -> int: ...
@@ -7,9 +7,4 @@ from fastapi_extra.database.service import ModelService
7
7
  from fastapi_extra.database.session import DefaultSession as Session
8
8
  from fastapi_extra.database.session import SessionFactory
9
9
 
10
- __all__ = [
11
- "SessionFactory",
12
- "Session",
13
- "SQLBase",
14
- "ModelService"
15
- ]
10
+ __all__ = ["SessionFactory", "Session", "SQLBase", "ModelService"]
@@ -15,8 +15,8 @@ from fastapi_extra.utils import get_machine_seed
15
15
 
16
16
  class AutoPK(SQLModel):
17
17
  id: int | None = Field(
18
- default=None,
19
- title="ID",
18
+ default=None,
19
+ title="ID",
20
20
  primary_key=True,
21
21
  sa_type=BigInteger,
22
22
  sa_column_kwargs={"autoincrement": True},
@@ -26,9 +26,9 @@ class AutoPK(SQLModel):
26
26
 
27
27
  class LocalPK(SQLModel):
28
28
  id: Cursor | None = Field(
29
- default_factory=_Cursor(get_machine_seed()).next_val,
30
- title="ID",
31
- primary_key=True,
29
+ default_factory=_Cursor(get_machine_seed()).next_val,
30
+ title="ID",
31
+ primary_key=True,
32
32
  sa_type=BigInteger,
33
33
  sa_column_kwargs={"autoincrement": False},
34
34
  schema_extra={"json_schema_extra": {"readOnly": True}},
@@ -53,7 +53,7 @@ class Versioned(SQLModel):
53
53
  sa_column_kwargs={"nullable": False, "comment": "VERSION_ID"},
54
54
  schema_extra={"json_schema_extra": {"readOnly": True}},
55
55
  )
56
-
56
+
57
57
  @declared_attr # type: ignore
58
58
  def __mapper_args__(cls) -> dict:
59
59
  return {"version_id_col": cls.version_id}
@@ -61,17 +61,26 @@ class Versioned(SQLModel):
61
61
 
62
62
  class Optime(SQLModel):
63
63
  create_at: LocalDateTime = Field(
64
- default_factory=datetime.datetime.now,
64
+ default_factory=datetime.datetime.now,
65
65
  title="CREATE_AT",
66
66
  sa_type=DateTime,
67
- sa_column_kwargs={"default": func.now(), "nullable": False, "comment": "CREATE_AT"},
67
+ sa_column_kwargs={
68
+ "default": func.now(),
69
+ "nullable": False,
70
+ "comment": "CREATE_AT",
71
+ },
68
72
  schema_extra={"json_schema_extra": {"readOnly": True}},
69
73
  )
70
74
  update_at: LocalDateTime = Field(
71
- default_factory=datetime.datetime.now,
75
+ default_factory=datetime.datetime.now,
72
76
  title="UPDATE_AT",
73
77
  sa_type=DateTime,
74
- sa_column_kwargs={"default": func.now(), "onupdate": func.now(), "nullable": False, "comment": "UPDATE_AT"},
78
+ sa_column_kwargs={
79
+ "default": func.now(),
80
+ "onupdate": func.now(),
81
+ "nullable": False,
82
+ "comment": "UPDATE_AT",
83
+ },
75
84
  schema_extra={"json_schema_extra": {"readOnly": True}},
76
85
  )
77
86
 
@@ -2,7 +2,7 @@ __author__ = "ziyan.yin"
2
2
  __date__ = "2025-01-12"
3
3
 
4
4
  from contextvars import ContextVar
5
- from typing import Any, Generic, Self, TypeVar
5
+ from typing import Any, Generic, TypeVar
6
6
 
7
7
  from fastapi_extra.database.model import SQLModel
8
8
  from fastapi_extra.database.session import AsyncSession, DefaultSession
@@ -13,24 +13,27 @@ Model = TypeVar("Model", bound=SQLModel)
13
13
 
14
14
  class ModelService(AbstractService, Generic[Model], abstract=True):
15
15
  __slot__ = ()
16
- __model__: Model
17
- __session_container__ = ContextVar("__session_container__", default=None)
18
-
16
+ __model__: type[Model]
17
+ __session_container__ = ContextVar[AsyncSession | None]("__session_container__", default=None)
18
+
19
19
  @classmethod
20
- def __class_getitem__(cls, item: type[SQLModel]) -> Self:
20
+ def __class_getitem__(cls, item: type[SQLModel]) -> type["ModelService"]:
21
21
  if not issubclass(item, SQLModel):
22
22
  raise TypeError(f"type[SQLModel] expected, got {item}")
23
23
  if not (table_arg := item.model_config.get("table", None)):
24
- raise AttributeError(f"True expected for argument {item.__name__}.model_config.table, got {table_arg}")
25
-
24
+ raise AttributeError(
25
+ f"True expected for argument {item.__name__}.model_config.table, got {table_arg}"
26
+ )
27
+
26
28
  class SubService(ModelService):
29
+ __slot__ = ()
27
30
  __model__ = item
28
-
31
+
29
32
  return SubService
30
33
 
31
34
  def __init__(self, session: DefaultSession):
32
35
  self.__session_container__.set(session)
33
-
36
+
34
37
  @property
35
38
  def session(self) -> AsyncSession:
36
39
  _session = self.__session_container__.get()
@@ -45,6 +48,6 @@ class ModelService(AbstractService, Generic[Model], abstract=True):
45
48
  self.session.add(model)
46
49
  await self.session.flush()
47
50
  return model
48
-
49
- async def delete(self, model: Model) -> Model:
51
+
52
+ async def delete(self, model: Model) -> None:
50
53
  return await self.session.delete(model)
@@ -5,7 +5,7 @@ from typing import Annotated, AsyncGenerator, Literal, Self
5
5
 
6
6
  from fastapi.params import Depends
7
7
  from pydantic import AnyUrl, BaseModel, Field
8
- from sqlalchemy.ext.asyncio import create_async_engine
8
+ from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
9
9
  from sqlmodel.ext.asyncio.session import AsyncSession
10
10
 
11
11
  from fastapi_extra.dependency import AbstractComponent
@@ -16,13 +16,16 @@ class DatabaseConfig(BaseModel):
16
16
  url: AnyUrl
17
17
  echo: bool = False
18
18
  echo_pool: bool = False
19
- isolation_level: Literal[
20
- "SERIALIZABLE",
21
- "REPEATABLE READ",
22
- "READ COMMITTED",
23
- "READ UNCOMMITTED",
24
- "AUTOCOMMIT",
25
- ] | None = None
19
+ isolation_level: (
20
+ Literal[
21
+ "SERIALIZABLE",
22
+ "REPEATABLE READ",
23
+ "READ COMMITTED",
24
+ "READ UNCOMMITTED",
25
+ "AUTOCOMMIT",
26
+ ]
27
+ | None
28
+ ) = None
26
29
  options: dict = Field(default_factory=dict)
27
30
 
28
31
 
@@ -36,18 +39,20 @@ _settings = DefaultDatabaseSettings() # type: ignore
36
39
  class SessionFactory(AbstractComponent):
37
40
  __slot__ = ("_engine",)
38
41
  default_config = _settings.datasource
39
-
42
+
40
43
  def __init__(self):
41
- self._engine = None
42
-
44
+ self._engine: AsyncEngine | None = None
45
+
43
46
  @classmethod
44
47
  def setup(cls, **options) -> Self:
45
48
  db = cls()
46
49
  db._engine = create_async_engine(
47
50
  url=str(cls.default_config.url),
48
- **cls.default_config.model_dump(exclude_defaults=True, exclude={"url", "options"}),
51
+ **cls.default_config.model_dump(
52
+ exclude_defaults=True, exclude={"url", "options"}
53
+ ),
49
54
  **cls.default_config.options,
50
- **options
55
+ **options,
51
56
  )
52
57
  return db
53
58
 
@@ -9,23 +9,19 @@ from fastapi import Depends, FastAPI, Request
9
9
 
10
10
 
11
11
  def async_wrapper(func: Callable):
12
-
12
+
13
13
  async def func_wrapper(*args, **kwds):
14
14
  return func(*args, **kwds)
15
-
15
+
16
16
  return update_wrapper(func_wrapper, func)
17
17
 
18
18
 
19
19
  class DependencyMetaClass(ABCMeta):
20
20
  __load__ = None
21
21
  __token__ = None
22
-
22
+
23
23
  def __new__(
24
- mcs,
25
- name: str,
26
- bases: tuple[type, ...],
27
- attrs: dict,
28
- abstract: bool = False
24
+ mcs, name: str, bases: tuple[type, ...], attrs: dict, abstract: bool = False
29
25
  ):
30
26
  new_cls = super().__new__(mcs, name, bases, attrs)
31
27
  new_cls.__token__ = f"{new_cls.__module__}.{new_cls.__name__}"
@@ -54,7 +50,9 @@ class AbstractComponent(metaclass=DependencyMetaClass, abstract=True):
54
50
  @final
55
51
  @classmethod
56
52
  async def __load__(cls, request: Request) -> Self:
57
- assert hasattr(request.app.state, cls.__token__), f"{cls.__name__} must be installed in lifespan"
53
+ assert hasattr(
54
+ request.app.state, cls.__token__
55
+ ), f"{cls.__name__} must be installed in lifespan"
58
56
  return getattr(request.app.state, cls.__token__)
59
57
 
60
58
  async def dispose(self) -> None:
fastapi_extra/form.py CHANGED
@@ -16,10 +16,12 @@ class DataRange(BaseModel, Generic[C]):
16
16
 
17
17
  class ColumnExpression(BaseModel, Generic[S]):
18
18
  column_name: str = Field(title="列名")
19
- option: Literal["eq", "ne", "gt", "lt", "ge", "le"] = Field(default="eq", title="逻辑值")
19
+ option: Literal["eq", "ne", "gt", "lt", "ge", "le"] = Field(
20
+ default="eq", title="逻辑值"
21
+ )
20
22
  value: S = Field(title="参考值")
21
-
22
- @model_validator(mode="after")
23
+
24
+ @model_validator(mode="after") # type: ignore
23
25
  def validate_value(self):
24
26
  if self.value is None and self.option not in ("eq", "ne"):
25
27
  raise ValueError("NoneType is not comparable")
@@ -27,7 +29,7 @@ class ColumnExpression(BaseModel, Generic[S]):
27
29
 
28
30
  class WhereClause(BaseModel):
29
31
  option: Literal["and", "or"] = Field(default="and", title="关系")
30
- column_clauses: list[ColumnExpression | "WhereClause"]
32
+ column_clauses: list["ColumnExpression | WhereClause"]
31
33
 
32
34
 
33
35
  class Page(BaseModel, Generic[Schema]):
@@ -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
fastapi_extra/response.py CHANGED
@@ -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
@@ -195,32 +195,53 @@ class APIResult(BaseModel, Generic[T]):
195
195
  data: T | None = Field(default=None, title="返回数据")
196
196
 
197
197
  if TYPE_CHECKING:
198
+
198
199
  @classmethod
199
200
  def ok(cls, data: T | None = None) -> "APIResult[T]":
200
201
  return APIResult(data=data)
202
+
201
203
  else:
204
+
202
205
  @classmethod
203
206
  def ok(cls, data: T | None = None) -> "APIResponse":
204
- return APIResponse(APIResult(data=data))
207
+ model = cls.__new__(cls)
208
+ model.__dict__["data"] = data
209
+ return APIResponse(model)
205
210
 
206
211
 
207
212
  class APIResponse(JSONResponse):
208
-
213
+
209
214
  def render(self, content: APIResult) -> bytes:
210
- return content.__pydantic_serializer__.to_json(
215
+ return APIResult.__pydantic_serializer__.to_json(
211
216
  content,
212
217
  indent=None,
213
218
  by_alias=True,
214
219
  exclude_defaults=False,
215
220
  exclude_none=False,
216
- exclude_unset=False
221
+ exclude_unset=False,
217
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
+
218
237
 
219
238
 
220
239
  class APIError(Exception):
221
240
  __slots__ = ("code", "message")
222
-
223
- def __init__(self, result: ResultEnum | None = None, code: str = "00000", message: str = "") -> None:
241
+
242
+ def __init__(
243
+ self, result: ResultEnum | None = None, code: str = "00000", message: str = ""
244
+ ) -> None:
224
245
  if result:
225
246
  self.code = result.value[0]
226
247
  self.message = message or result.value[1]
@@ -228,7 +249,7 @@ class APIError(Exception):
228
249
  self.code = code
229
250
  self.message = message
230
251
  super().__init__(self)
231
-
252
+
232
253
  def __str__(self) -> str:
233
254
  return self.message
234
255
 
Binary file
fastapi_extra/routing.pyi CHANGED
@@ -1,16 +1,11 @@
1
1
  __author__ = "ziyan.yin"
2
2
  __describe__ = ""
3
3
 
4
-
5
4
  from typing import Any
6
5
 
7
6
  from fastapi import FastAPI
8
7
 
9
8
  class RouteNode:
9
+ def add_route(self, fullpath: str, handler: Any): ...
10
10
 
11
- def add_route(self, fullpath: str, handler: Any):
12
- ...
13
-
14
-
15
- def install(app: FastAPI) -> None:
16
- ...
11
+ def install(app: FastAPI) -> None: ...
fastapi_extra/settings.py CHANGED
@@ -11,18 +11,18 @@ from pydantic_settings import (BaseSettings, PydanticBaseSettingsSource,
11
11
 
12
12
  class Settings(BaseSettings):
13
13
  model_config = SettingsConfigDict(
14
- toml_file=["config.default.toml", "config.custom.toml"],
14
+ toml_file=["config.default.toml", "config.custom.toml"],
15
15
  validate_default=False,
16
- extra="ignore"
16
+ extra="ignore",
17
17
  )
18
-
18
+
19
19
  title: str = "FastAPI"
20
20
  version: str = "0.1.0"
21
21
  debug: bool = False
22
22
  root_path: str = ""
23
23
  include_in_schema: bool = True
24
24
  mode: Literal["dev", "test", "prod"] = "dev"
25
-
25
+
26
26
  @classmethod
27
27
  def settings_customise_sources(
28
28
  cls,
@@ -33,10 +33,10 @@ class Settings(BaseSettings):
33
33
  file_secret_settings: PydanticBaseSettingsSource,
34
34
  ) -> Tuple[PydanticBaseSettingsSource, ...]:
35
35
  return (
36
- TomlConfigSettingsSource(settings_cls),
37
- env_settings,
36
+ TomlConfigSettingsSource(settings_cls),
37
+ env_settings,
38
38
  init_settings,
39
- file_secret_settings
39
+ file_secret_settings,
40
40
  )
41
41
 
42
42
  @model_validator(mode="after")
fastapi_extra/types.py CHANGED
@@ -9,7 +9,9 @@ from typing import Annotated, Any, TypeVar, Union
9
9
  from pydantic import BaseModel, PlainSerializer
10
10
  from sqlmodel import SQLModel
11
11
 
12
- Comparable = Union[int, float, decimal.Decimal, datetime.datetime, datetime.date, datetime.time]
12
+ Comparable = Union[
13
+ int, float, decimal.Decimal, datetime.datetime, datetime.date, datetime.time
14
+ ]
13
15
  Serializable = Union[Comparable, bool, str, None]
14
16
 
15
17
 
@@ -20,9 +22,8 @@ S = TypeVar("S", bound=Serializable)
20
22
  Schema = TypeVar("Schema", bound=BaseModel)
21
23
  Model = TypeVar("Model", bound=SQLModel)
22
24
 
23
- Cursor = Annotated[
24
- int, PlainSerializer(lambda x: str(x), return_type=str)
25
- ]
25
+ Cursor = Annotated[int, PlainSerializer(lambda x: str(x), return_type=str)]
26
26
  LocalDateTime = Annotated[
27
- datetime.datetime, PlainSerializer(lambda x: x.strftime("%Y-%m-%d %H:%M:%S"), return_type=str)
27
+ datetime.datetime,
28
+ PlainSerializer(lambda x: x.strftime("%Y-%m-%d %H:%M:%S"), return_type=str),
28
29
  ]
@@ -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.2.4
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.116.0,>=0.115.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.7.0
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,29 @@
1
+ fastapi_extra/__init__.py,sha256=wgNT6dUITkXf69b2m5-YVabRIJRzirouJfBh3nLnQKg,556
2
+ fastapi_extra/_patch.py,sha256=WpuAsjBRKgU5fgmGPhAdm68jc_QAArsZyKuYzO1LTuI,1194
3
+ fastapi_extra/cursor.cp312-win_amd64.pyd,sha256=yb4XpcrI2yyiV0s8MjYO8wIZlTwxeLv8GynyTHg6fnA,52224
4
+ fastapi_extra/cursor.pyi,sha256=9VRlz_g1lPEqn_03thmwJga7aELGp--jvqySN7f_4iM,158
5
+ fastapi_extra/dependency.py,sha256=cnmZjoL9DVZq8qHAkLVhDX3RIvCWUMdxN0dB7obZruc,2106
6
+ fastapi_extra/form.py,sha256=jwaMfHiILp_wUlP-BRA-Gp3zp42T5mrZjJp0CALU5So,1275
7
+ fastapi_extra/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ fastapi_extra/response.py,sha256=xLZs0oVf3fs1BF613UpDSx5XsrLmsCTfPibWujfqM9s,10827
9
+ fastapi_extra/routing.cp312-win_amd64.pyd,sha256=kjqn56w9U2xrJB2mEfcJ8PwlvVF3n8j2_RLR_3H0hH8,90112
10
+ fastapi_extra/routing.pyi,sha256=0HdMRqaeAtT7kM9GFMkffOeNeNwKPK1YqtQ40SDMKew,223
11
+ fastapi_extra/settings.py,sha256=PsjsdDvGR55spOFB6VUArzvwO7GsgZEwYKat-NXnN9s,1452
12
+ fastapi_extra/types.py,sha256=8uG5vwWsYh5Wq7KORKmK31F4cw11ReCD9Nx6Tv2D_MU,825
13
+ fastapi_extra/urlparse.cp312-win_amd64.pyd,sha256=oowDmGfQpXJg2Rr9FpC6Tj0AURyb9aRgAcooX8Ip_d8,44544
14
+ fastapi_extra/urlparse.pyi,sha256=1FDp46XKqTrlJHlnbqK_NyzBkCYRpHEINERtNsMyvWI,275
15
+ fastapi_extra/utils.py,sha256=tsPX3kpF_P5D9Bd3gnlG6rkVsLkv5gbxjml-s6ZL_6I,346
16
+ fastapi_extra/cache/__init__.py,sha256=Kq5eCF53aGIFch14xDj_SCiK5IvY7A0jX28st-ergls,114
17
+ fastapi_extra/cache/redis.py,sha256=Zcoyn98d7uyp6p07sssjjo_TcG-kyjPj-D-zr4C8liU,1624
18
+ fastapi_extra/database/__init__.py,sha256=qmZ_3InumrYF-Gku6-f1ohnwG5qw_OGQU6b5QvYEYRs,361
19
+ fastapi_extra/database/model.py,sha256=jVLyd9zVsPQn_9ahfPkneUtM3xtGE-q2_osNdFpPBSw,2557
20
+ fastapi_extra/database/service.py,sha256=uc_1VlExIapSoQMpLUhckA_gBLW1bGXLVwTy2uz3sD0,1895
21
+ fastapi_extra/database/session.py,sha256=fIC5Pk7C-kiF2alFJpW02_P5aoFZrAP3LtJwSelHj4Y,2011
22
+ fastapi_extra/native/cursor.pyx,sha256=GchJIPY6e5scuyl1BbA-Et0CdRcHOI3xgsTvDem0B70,1141
23
+ fastapi_extra/native/routing.pyx,sha256=NisJ9YaxzceDVWJnF3EeVXWT8rv_6WRDuIfLEK0eWbc,6233
24
+ fastapi_extra/native/urlparse.pyx,sha256=LJWPyZlajYkjBoin65NgeOjrdR9wKabrB5Lpr8edgIU,1406
25
+ fastapi_extra-0.3.0.dist-info/licenses/LICENSE,sha256=0vTjHDa3VDsxTT-R-sH6SpYcA2F1hKtbX9ZFZQm-EcU,1516
26
+ fastapi_extra-0.3.0.dist-info/METADATA,sha256=wAmRDRVtVIKTgpyr6Mbb0ulTn-brtEN4Ug7jSBj2_Ew,1372
27
+ fastapi_extra-0.3.0.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101
28
+ fastapi_extra-0.3.0.dist-info/top_level.txt,sha256=B7D80bEftE2E-eSd1be2r9BWkLLMZN21dRTWpb4y4Ig,14
29
+ fastapi_extra-0.3.0.dist-info/RECORD,,
@@ -1,25 +0,0 @@
1
- fastapi_extra/__init__.py,sha256=YZi6jXNmOG_XEyB811NuUdFqvrfI-g3vfjWjtrZUex4,286
2
- fastapi_extra/cursor.cp312-win_amd64.pyd,sha256=f5grsVRhjeN6RnJ2Ew18qK05WGtnAmBbeB2XPPSm_Ic,53760
3
- fastapi_extra/cursor.pyi,sha256=t1_ub-dRhu3OcXB_dIw5MdBG9r1n7853Vtgzc6bk6dw,115
4
- fastapi_extra/dependency.py,sha256=LtYnOTMyhOQUFSbNEViw7lxJvAFpPWbyuY4e2goSG-8,2130
5
- fastapi_extra/form.py,sha256=Fs9uEDOQThjFroDVTrjWnIGJ107BgXCppIVTymwQLzg,1247
6
- fastapi_extra/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- fastapi_extra/response.py,sha256=CQXWyRYmQx12VNwGLGOjDaKvWuMTBPrtIldZT5UF8fM,10195
8
- fastapi_extra/routing.cp312-win_amd64.pyd,sha256=-m_NRsS17Xn1mHR_gu89XeuayzXUEPTBFzcmfbW2dfI,91648
9
- fastapi_extra/routing.pyi,sha256=pW9O3noU4F-7l7LLViTVBLgzY468JS0jO96vdfL7CPA,243
10
- fastapi_extra/settings.py,sha256=cCcwaper5GiNNoT4gNKqf-iloSOTNnMsiUR0knJx4Mw,1461
11
- fastapi_extra/types.py,sha256=3z6gUnao6WZL76asZYmex20xfY9mvYA-RbnsxUcui30,819
12
- fastapi_extra/utils.py,sha256=tsPX3kpF_P5D9Bd3gnlG6rkVsLkv5gbxjml-s6ZL_6I,346
13
- fastapi_extra/cache/__init__.py,sha256=kq4b_AYKCSJ0fEp4rqpeaoNJilko4XbtfC81xzUaYGI,122
14
- fastapi_extra/cache/redis.py,sha256=-hr2DRkmruzH4cIArdjsytqRiiWWtDJt9GIDy38wmtQ,1600
15
- fastapi_extra/database/__init__.py,sha256=pCYUoEylTponWqpR0AXJHcRo_cs4fnEXVVV9B5J9rt0,384
16
- fastapi_extra/database/model.py,sha256=2lDi9PQ5F0PSM7BGZozZf1wSefpXnTWqAVzEyGPaXRI,2453
17
- fastapi_extra/database/service.py,sha256=V5ojRpiWs9_B3XVQz-PtyvBePfmByTn8WG2gXwuhpO0,1828
18
- fastapi_extra/database/session.py,sha256=PALArHhXNS2gCgeMkiKjyatvINV_VW1LjgEIwXDKyfQ,1903
19
- fastapi_extra/native/cursor.pyx,sha256=GchJIPY6e5scuyl1BbA-Et0CdRcHOI3xgsTvDem0B70,1141
20
- fastapi_extra/native/routing.pyx,sha256=NisJ9YaxzceDVWJnF3EeVXWT8rv_6WRDuIfLEK0eWbc,6233
21
- fastapi_extra-0.2.4.dist-info/licenses/LICENSE,sha256=0vTjHDa3VDsxTT-R-sH6SpYcA2F1hKtbX9ZFZQm-EcU,1516
22
- fastapi_extra-0.2.4.dist-info/METADATA,sha256=SCUpJNqiFVxVbVRtPj6Y-g0zXCPRWc4d6QXK6zdmX-E,1371
23
- fastapi_extra-0.2.4.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101
24
- fastapi_extra-0.2.4.dist-info/top_level.txt,sha256=B7D80bEftE2E-eSd1be2r9BWkLLMZN21dRTWpb4y4Ig,14
25
- fastapi_extra-0.2.4.dist-info/RECORD,,