fastapi-extra 0.1.4__cp312-cp312-win_amd64.whl → 0.1.5__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,4 +1,4 @@
1
- __version__ = "0.1.4"
1
+ __version__ = "0.1.5"
2
2
 
3
3
 
4
4
  from fastapi import FastAPI
@@ -0,0 +1,10 @@
1
+ __author__ = "ziyan.yin"
2
+ __date__ = "2025-01-10"
3
+
4
+ from .redis import Redis, RedisCli, RedisMaker
5
+
6
+ __all__ = [
7
+ "Redis",
8
+ "RedisMaker",
9
+ "RedisCli"
10
+ ]
@@ -0,0 +1,52 @@
1
+ __author__ = "ziyan.yin"
2
+ __date__ = "2025-01-17"
3
+
4
+
5
+ from typing import Annotated, AsyncGenerator
6
+
7
+ from fastapi.params import Depends
8
+ from pydantic import BaseModel, Field, RedisDsn
9
+ from redis.asyncio import ConnectionPool, Redis
10
+
11
+ from fastapi_extra.settings import Settings
12
+
13
+
14
+ class RedisConfig(BaseModel):
15
+ url: RedisDsn = RedisDsn("redis://localhost:6379/0")
16
+ max_connections: int | None = None
17
+ connection_kwargs: dict = Field(default_factory=dict)
18
+
19
+
20
+ class DefaultRedisSettings(Settings):
21
+ redis: RedisConfig
22
+
23
+
24
+ def load_pool(config: RedisConfig) -> ConnectionPool:
25
+ return ConnectionPool.from_url(
26
+ config.url,
27
+ **config.model_dump(exclude_defaults=True, exclude={"url", "connection_kwargs"}),
28
+ **config.connection_kwargs
29
+ )
30
+
31
+
32
+ _settings = DefaultRedisSettings() # type: ignore
33
+ DEFAULT_POOL = load_pool(_settings.redis)
34
+
35
+
36
+ async def dispose() -> None:
37
+ await DEFAULT_POOL.aclose()
38
+
39
+
40
+ class RedisMaker(Depends):
41
+
42
+ def __init__(self, pool: ConnectionPool):
43
+ super().__init__()
44
+ self.dependency = self
45
+ self.pool = pool
46
+
47
+ async def __call__(self) -> AsyncGenerator[Redis, None]:
48
+ async with Redis(connection_pool=self.pool) as session:
49
+ yield session
50
+
51
+
52
+ RedisCli = Annotated[Redis, RedisMaker(DEFAULT_POOL)]
Binary file
@@ -0,0 +1,17 @@
1
+ __author__ = "ziyan.yin"
2
+ __date__ = "2025-01-05"
3
+
4
+
5
+ from fastapi_extra.database.model import SQLBase
6
+ from fastapi_extra.database.service import ModelService
7
+ from fastapi_extra.database.session import AsyncSessionMaker
8
+ from fastapi_extra.database.session import DefaultSession as Session
9
+ from fastapi_extra.database.session import SessionMaker
10
+
11
+ __all__ = [
12
+ "AsyncSessionMaker",
13
+ "ModelService",
14
+ "Session",
15
+ "SessionMaker",
16
+ "SQLBase"
17
+ ]
@@ -0,0 +1,50 @@
1
+ __author__ = "ziyan.yin"
2
+ __date__ = "2024-12-26"
3
+
4
+
5
+ from typing import Any, Literal
6
+
7
+ from pydantic import AnyUrl, BaseModel, Field
8
+ from sqlalchemy import Engine, NullPool
9
+ from sqlalchemy.util import _concurrency_py3k
10
+ from sqlmodel import create_engine
11
+
12
+ from fastapi_extra.settings import Settings
13
+
14
+
15
+ class DatabaseConfig(BaseModel):
16
+ url: AnyUrl
17
+ echo: bool = False
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
26
+ options: dict = Field(default_factory=dict)
27
+
28
+
29
+ class DefaultDatabaseSettings(Settings):
30
+ datasource: DatabaseConfig
31
+
32
+
33
+ def load_engine(config: DatabaseConfig, **kw: Any) -> Engine:
34
+ return create_engine(
35
+ url=str(config.url),
36
+ **config.model_dump(exclude_defaults=True, exclude={"url", "options"}),
37
+ **config.options,
38
+ **kw
39
+ )
40
+
41
+
42
+ _settings = DefaultDatabaseSettings() # type: ignore
43
+ if _settings.mode == "test":
44
+ DEFAULT_ENGINE: Engine = load_engine(_settings.datasource, poolclass=NullPool)
45
+ else:
46
+ DEFAULT_ENGINE: Engine = load_engine(_settings.datasource)
47
+
48
+
49
+ async def dispose() -> None:
50
+ await _concurrency_py3k.greenlet_spawn(DEFAULT_ENGINE.dispose)
@@ -0,0 +1,80 @@
1
+ __author__ = "ziyan.yin"
2
+ __date__ = "2024-12-25"
3
+
4
+
5
+ import datetime
6
+
7
+ from sqlalchemy import BigInteger, DateTime, Integer, SmallInteger, func
8
+ from sqlalchemy.ext.declarative import declared_attr
9
+ from sqlmodel import Field, SQLModel
10
+
11
+ from fastapi_extra.cursor import Cursor as _Cursor # type: ignore
12
+ from fastapi_extra.types import Cursor, LocalDateTime
13
+ from fastapi_extra.utils import get_machine_seed
14
+
15
+
16
+ class AutoPK(SQLModel):
17
+ id: int | None = Field(
18
+ default_factory=lambda: None,
19
+ title="ID",
20
+ primary_key=True,
21
+ sa_type=BigInteger,
22
+ sa_column_kwargs={"autoincrement": True},
23
+ schema_extra={"json_schema_extra": {"readOnly": True}},
24
+ )
25
+
26
+
27
+ class LocalPK(SQLModel):
28
+ id: Cursor | None = Field(
29
+ default_factory=_Cursor(get_machine_seed()).next_val,
30
+ title="ID",
31
+ primary_key=True,
32
+ sa_type=BigInteger,
33
+ sa_column_kwargs={"autoincrement": False},
34
+ schema_extra={"json_schema_extra": {"readOnly": True}},
35
+ )
36
+
37
+
38
+ class Deleted(SQLModel):
39
+ deleted: int = Field(
40
+ default=0,
41
+ title="DELETED",
42
+ sa_type=SmallInteger,
43
+ sa_column_kwargs={"nullable": False, "comment": "DELETED"},
44
+ schema_extra={"json_schema_extra": {"readOnly": True}},
45
+ )
46
+
47
+
48
+ class Versioned(SQLModel):
49
+ version_id: int = Field(
50
+ default=0,
51
+ title="VERSION_ID",
52
+ sa_type=Integer,
53
+ sa_column_kwargs={"nullable": False, "comment": "VERSION_ID"},
54
+ schema_extra={"json_schema_extra": {"readOnly": True}},
55
+ )
56
+
57
+ @declared_attr # type: ignore
58
+ def __mapper_args__(cls) -> dict:
59
+ return {"version_id_col": "version_id"}
60
+
61
+
62
+ class Optime(SQLModel):
63
+ create_at: LocalDateTime = Field(
64
+ default_factory=datetime.datetime.now,
65
+ title="CREATE_AT",
66
+ sa_type=DateTime,
67
+ sa_column_kwargs={"default": func.now(), "nullable": False, "comment": "CREATE_AT"},
68
+ schema_extra={"json_schema_extra": {"readOnly": True}},
69
+ )
70
+ update_at: LocalDateTime = Field(
71
+ default_factory=datetime.datetime.now,
72
+ title="UPDATE_AT",
73
+ sa_type=DateTime,
74
+ sa_column_kwargs={"default": func.now(), "onupdate": func.now(), "nullable": False, "comment": "UPDATE_AT"},
75
+ schema_extra={"json_schema_extra": {"readOnly": True}},
76
+ )
77
+
78
+
79
+ class SQLBase(LocalPK, Versioned, Deleted, Optime):
80
+ pass
@@ -0,0 +1,40 @@
1
+ __author__ = "ziyan.yin"
2
+ __date__ = "2025-01-12"
3
+
4
+ from typing import Any, Generic, Self, TypeVar
5
+
6
+ from fastapi_extra.database.model import SQLModel
7
+ from fastapi_extra.database.session import DefaultSession
8
+ from fastapi_extra.dependency import AbstractDependency
9
+
10
+ Model = TypeVar("Model", bound=SQLModel)
11
+
12
+
13
+ class ModelService(AbstractDependency, Generic[Model], annotated=False):
14
+ __slot__ = ("session", )
15
+ __model__: SQLModel
16
+
17
+ @classmethod
18
+ def __class_getitem__(cls, item: type[SQLModel]) -> Self:
19
+ if not issubclass(item, SQLModel):
20
+ raise TypeError(f"type[SQLModel] expected, got {item}")
21
+ if not (table_arg := item.model_config.get("table", None)):
22
+ raise AttributeError(f"True expected for argument {item.__name__}.model_config.table, got {table_arg}")
23
+ cls.__model__ = item
24
+ return cls
25
+
26
+ def __init__(self, session: DefaultSession):
27
+ self.session = session
28
+
29
+ async def get(self, ident: int | str, **kwargs: Any) -> Model | None:
30
+ return await self.session.get(self.__model__, ident, **kwargs)
31
+
32
+ async def create(self, model: Model) -> Model:
33
+ return await self.session.add(model)
34
+
35
+ async def create_model(self, **kwargs: Any) -> Model:
36
+ model = self.__model__.model_validate(kwargs)
37
+ return self.create(model)
38
+
39
+ async def delete(self, model: Model) -> Model:
40
+ return await self.session.delete(model)
@@ -0,0 +1,39 @@
1
+ __author__ = "ziyan.yin"
2
+ __date__ = "2025-01-05"
3
+
4
+
5
+ from typing import Annotated, AsyncGenerator, Generator
6
+
7
+ from fastapi.params import Depends
8
+ from sqlalchemy.ext.asyncio import AsyncEngine
9
+ from sqlmodel import Session as _Session
10
+ from sqlmodel.ext.asyncio.session import AsyncSession
11
+
12
+ from fastapi_extra.database.engine import DEFAULT_ENGINE, Engine
13
+
14
+
15
+ class SessionMaker(Depends):
16
+ __slots__ = ("engine", )
17
+
18
+ def __init__(self, engine: Engine):
19
+ super().__init__()
20
+ self.engine = engine
21
+ self.dependency = self
22
+
23
+ def __call__(self) -> Generator[_Session, None, None]:
24
+ with _Session(self.engine) as session:
25
+ yield session
26
+
27
+
28
+ class AsyncSessionMaker(SessionMaker):
29
+
30
+ def __init__(self, engine: Engine):
31
+ super().__init__(engine)
32
+ self.async_engine: AsyncEngine = AsyncEngine(self.engine)
33
+
34
+ async def __call__(self) -> AsyncGenerator[AsyncSession, None]:
35
+ async with AsyncSession(self.async_engine) as session:
36
+ yield session
37
+
38
+
39
+ DefaultSession = Annotated[AsyncSession, AsyncSessionMaker(DEFAULT_ENGINE)]
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: fastapi-extra
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: extra package for fastapi.
5
5
  Author-email: Ziyan Yin <408856732@qq.com>
6
6
  License: BSD-3-Clause
@@ -0,0 +1,23 @@
1
+ fastapi_extra/__init__.py,sha256=lG8uGj4bf5IlFbIznHTkpa5IGXFcxcBfCa2x-b_HhXY,286
2
+ fastapi_extra/cursor.cp312-win_amd64.pyd,sha256=kWtFGDu_zSoytLufV74NuUciTAasxrJ73d5SlDpPWVo,57344
3
+ fastapi_extra/dependency.py,sha256=Pgl4Y9Mm6JY5pw19w_xJEmnnLkQ9p_K1h1w9lLVHUJQ,907
4
+ fastapi_extra/form.py,sha256=LikaJkA16dSRGCqX9K7z2S8-e3SJcMiVXX5nRZU_kVY,957
5
+ fastapi_extra/response.py,sha256=DHvhOSgwot5eBNKuI_jPYxZ5rshZ55Xkg-FNBJlHD1E,9609
6
+ fastapi_extra/routing.cp312-win_amd64.pyd,sha256=LSLlg7Ld5TtvJ46jhobMRuCCk5tsZqu6kcA86_J4Zk4,94720
7
+ fastapi_extra/settings.py,sha256=cCcwaper5GiNNoT4gNKqf-iloSOTNnMsiUR0knJx4Mw,1461
8
+ fastapi_extra/types.py,sha256=EUjT9jFryzlazHvWs4m-IfUezmSEvyxwaOGe_vTTBnY,763
9
+ fastapi_extra/utils.py,sha256=tsPX3kpF_P5D9Bd3gnlG6rkVsLkv5gbxjml-s6ZL_6I,346
10
+ fastapi_extra/cache/__init__.py,sha256=pg3VTyLBPy3j1pop_RSGLhaQqnUSNv0oznaOSjxM9rw,168
11
+ fastapi_extra/cache/redis.py,sha256=6QNicKfn8_zkbL0m-mVAWcv5UrAbmH_ZZWz8xA7ES_w,1352
12
+ fastapi_extra/database/__init__.py,sha256=GIWWUF-diioMsKW63x6lKpLWaRPCwTCZtr8n-EX3twc,468
13
+ fastapi_extra/database/engine.py,sha256=vENq4-3mern_Nvd2n0GC5VeEvL6Ruv7uxutMBDpEJA8,1335
14
+ fastapi_extra/database/model.py,sha256=icHh6tnVKYVGl0hNX6pYypTiyGQt3g41geOkjBZTTv4,2467
15
+ fastapi_extra/database/service.py,sha256=efDZuz__RqEom-UZHfKQ3rHkxnEYmQocWduVbm3rcy0,1478
16
+ fastapi_extra/database/session.py,sha256=KlzsZMQ1sHnUnYwLcI7AxY31vusmn_6aBT_YhsECQic,1152
17
+ fastapi_extra/native/cursor.pyx,sha256=bESprFDgk9gGjyPQ4YCSg51dov2WB6s60XrOs3r5-r0,1146
18
+ fastapi_extra/native/routing.pyx,sha256=GrdGAoBospwCpxMHBon5cuRYcz9ifAFSSYa2Ytf49lg,3841
19
+ fastapi_extra-0.1.5.dist-info/LICENSE,sha256=0vTjHDa3VDsxTT-R-sH6SpYcA2F1hKtbX9ZFZQm-EcU,1516
20
+ fastapi_extra-0.1.5.dist-info/METADATA,sha256=5QzhRf1SGhVn8SHL35vQepsAbEREiOGoYzhAo4ambkk,1348
21
+ fastapi_extra-0.1.5.dist-info/WHEEL,sha256=cRmSBGD-cl98KkuHMNqv9Ac9L9_VqTvcBYwpIvxN0cg,101
22
+ fastapi_extra-0.1.5.dist-info/top_level.txt,sha256=B7D80bEftE2E-eSd1be2r9BWkLLMZN21dRTWpb4y4Ig,14
23
+ fastapi_extra-0.1.5.dist-info/RECORD,,
@@ -1,16 +0,0 @@
1
- fastapi_extra/__init__.py,sha256=wZGS0_cF9HspqetdvcDTIxjV9lp-0yTS7toLQQnJI0Q,286
2
- fastapi_extra/cursor.cp312-win_amd64.pyd,sha256=Zj_hwMRczIkzNkXjW3dUeNqrpBXW-hcTyNPlHSYxW9s,57344
3
- fastapi_extra/dependency.py,sha256=Pgl4Y9Mm6JY5pw19w_xJEmnnLkQ9p_K1h1w9lLVHUJQ,907
4
- fastapi_extra/form.py,sha256=LikaJkA16dSRGCqX9K7z2S8-e3SJcMiVXX5nRZU_kVY,957
5
- fastapi_extra/response.py,sha256=DHvhOSgwot5eBNKuI_jPYxZ5rshZ55Xkg-FNBJlHD1E,9609
6
- fastapi_extra/routing.cp312-win_amd64.pyd,sha256=4Vlhy3oYaYhUzj9jxQuONzlLYjfo03OmTsCg8jUUbcQ,94720
7
- fastapi_extra/settings.py,sha256=cCcwaper5GiNNoT4gNKqf-iloSOTNnMsiUR0knJx4Mw,1461
8
- fastapi_extra/types.py,sha256=EUjT9jFryzlazHvWs4m-IfUezmSEvyxwaOGe_vTTBnY,763
9
- fastapi_extra/utils.py,sha256=tsPX3kpF_P5D9Bd3gnlG6rkVsLkv5gbxjml-s6ZL_6I,346
10
- fastapi_extra/native/cursor.pyx,sha256=bESprFDgk9gGjyPQ4YCSg51dov2WB6s60XrOs3r5-r0,1146
11
- fastapi_extra/native/routing.pyx,sha256=GrdGAoBospwCpxMHBon5cuRYcz9ifAFSSYa2Ytf49lg,3841
12
- fastapi_extra-0.1.4.dist-info/LICENSE,sha256=0vTjHDa3VDsxTT-R-sH6SpYcA2F1hKtbX9ZFZQm-EcU,1516
13
- fastapi_extra-0.1.4.dist-info/METADATA,sha256=2YlZPZ_9Y8rbBVG2th19mmT12zzXuBTt7MQDsRtgIjo,1348
14
- fastapi_extra-0.1.4.dist-info/WHEEL,sha256=cRmSBGD-cl98KkuHMNqv9Ac9L9_VqTvcBYwpIvxN0cg,101
15
- fastapi_extra-0.1.4.dist-info/top_level.txt,sha256=B7D80bEftE2E-eSd1be2r9BWkLLMZN21dRTWpb4y4Ig,14
16
- fastapi_extra-0.1.4.dist-info/RECORD,,