fastapi-sqla 3.1.2__py3-none-any.whl → 3.3.0__py3-none-any.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_sqla/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- from fastapi_sqla.base import setup
1
+ from fastapi_sqla.base import setup, setup_middlewares, startup
2
2
  from fastapi_sqla.models import Collection, Item, Page
3
3
  from fastapi_sqla.pagination import Paginate, PaginateSignature, Pagination
4
4
  from fastapi_sqla.sqla import (
@@ -22,6 +22,8 @@ __all__ = [
22
22
  "SqlaSession",
23
23
  "open_session",
24
24
  "setup",
25
+ "setup_middlewares",
26
+ "startup",
25
27
  ]
26
28
 
27
29
 
@@ -28,7 +28,6 @@ def db_host():
28
28
  When CI key is set in environment variables, it uses `postgres` as host name else,
29
29
  host used is `localhost`
30
30
  """
31
-
32
31
  return "postgres" if "CI" in os.environ else "localhost"
33
32
 
34
33
 
@@ -38,7 +37,6 @@ def db_user():
38
37
 
39
38
  postgres
40
39
  """
41
-
42
40
  return "postgres"
43
41
 
44
42
 
@@ -48,7 +46,6 @@ def db_url(db_host, db_user):
48
46
 
49
47
  db url example postgresql://{db_user}@{db_host}/postgres
50
48
  """
51
-
52
49
  return f"postgresql://{db_user}@{db_host}/postgres"
53
50
 
54
51
 
@@ -107,7 +104,6 @@ def sqla_reflection(sqla_modules, sqla_connection):
107
104
  @fixture
108
105
  def patch_engine_from_config(request, sqla_connection):
109
106
  """So that all DB operations are never written to db for real."""
110
-
111
107
  if "dont_patch_engines" in request.keywords:
112
108
  yield
113
109
  else:
@@ -153,7 +149,7 @@ def async_sqlalchemy_url(db_url):
153
149
  return format_async_async_sqlalchemy_url(db_url)
154
150
 
155
151
 
156
- if asyncio_support: # noqa: C901
152
+ if asyncio_support:
157
153
 
158
154
  @fixture
159
155
  def async_engine(async_sqlalchemy_url):
@@ -167,7 +163,6 @@ if asyncio_support: # noqa: C901
167
163
  @fixture
168
164
  async def patch_new_engine(request, async_sqla_connection):
169
165
  """So that all async DB operations are never written to db for real."""
170
-
171
166
  if "dont_patch_engines" in request.keywords:
172
167
  yield
173
168
  else:
@@ -1,6 +1,6 @@
1
1
  import math
2
- from collections.abc import Awaitable, Callable
3
- from typing import Annotated, Iterator, Optional, Union, cast
2
+ from collections.abc import Awaitable, Callable, Iterator
3
+ from typing import Annotated, Optional, Union, cast
4
4
 
5
5
  from fastapi import Depends, Query
6
6
  from sqlalchemy.sql import Select, func, select
@@ -20,7 +20,8 @@ def setup(engine: Engine):
20
20
  aws_rds_iam_enabled = lc_environ.get("fastapi_sqla_aws_rds_iam_enabled") == "true"
21
21
 
22
22
  if aws_rds_iam_enabled:
23
- assert boto3_installed, boto3_installed_err
23
+ if not boto3_installed:
24
+ raise ImportError(f"boto3 is required for RDS IAM : {boto3_installed_err}")
24
25
  # Cache the client at startup
25
26
  get_rds_client()
26
27
  event.listen(engine, "do_connect", set_connection_token)
fastapi_sqla/base.py CHANGED
@@ -2,6 +2,7 @@ import functools
2
2
  import os
3
3
  import re
4
4
 
5
+ from deprecated import deprecated
5
6
  from fastapi import FastAPI
6
7
  from sqlalchemy.engine import Engine
7
8
 
@@ -20,6 +21,33 @@ except ImportError as err: # pragma: no cover
20
21
  _ENGINE_KEYS_REGEX = re.compile(r"fastapi_sqla__(?!_)(.+)(?<!_)__(?!_).+")
21
22
 
22
23
 
24
+ async def startup():
25
+ engine_keys = _get_engine_keys()
26
+ engines = {key: sqla.new_engine(key) for key in engine_keys}
27
+ for key, engine in engines.items():
28
+ if not _is_async_dialect(engine):
29
+ sqla.startup(key=key)
30
+ else:
31
+ await async_sqla.startup(key=key)
32
+
33
+
34
+ def setup_middlewares(app: FastAPI):
35
+ engine_keys = _get_engine_keys()
36
+ engines = {key: sqla.new_engine(key) for key in engine_keys}
37
+ for key, engine in engines.items():
38
+ if not _is_async_dialect(engine):
39
+ app.middleware("http")(
40
+ functools.partial(sqla.add_session_to_request, key=key)
41
+ )
42
+ else:
43
+ app.middleware("http")(
44
+ functools.partial(async_sqla.add_session_to_request, key=key)
45
+ )
46
+
47
+
48
+ @deprecated(
49
+ reason="FastAPI events are deprecated. This function will be remove in the upcoming major release." # noqa: E501
50
+ )
23
51
  def setup(app: FastAPI):
24
52
  engine_keys = _get_engine_keys()
25
53
  engines = {key: sqla.new_engine(key) for key in engine_keys}
@@ -30,7 +58,6 @@ def setup(app: FastAPI):
30
58
  functools.partial(sqla.add_session_to_request, key=key)
31
59
  )
32
60
  else:
33
- assert has_asyncio_support, asyncio_support_err
34
61
  app.add_event_handler(
35
62
  "startup", functools.partial(async_sqla.startup, key=key)
36
63
  )
fastapi_sqla/models.py CHANGED
@@ -3,7 +3,7 @@ from typing import Generic, TypeVar
3
3
  from pydantic import BaseModel, Field
4
4
  from pydantic import __version__ as pydantic_version
5
5
 
6
- major, _, _ = [int(v) for v in pydantic_version.split(".")]
6
+ major, _, _ = (int(v) for v in pydantic_version.split("."))
7
7
  is_pydantic2 = major == 2
8
8
  if is_pydantic2:
9
9
  GenericModel = BaseModel
@@ -1,7 +1,7 @@
1
1
  import math
2
- from collections.abc import Callable
2
+ from collections.abc import Callable, Iterator
3
3
  from functools import singledispatch
4
- from typing import Annotated, Iterator, Optional, Union, cast
4
+ from typing import Annotated, Optional, Union, cast
5
5
 
6
6
  from fastapi import Depends, Query
7
7
  from sqlalchemy.orm import Query as LegacyQuery
@@ -52,7 +52,7 @@ def paginate_query(
52
52
  limit: int,
53
53
  scalars: bool = True,
54
54
  ) -> Page: # pragma: no cover
55
- "Dispatch on registered functions based on `query` type"
55
+ """Dispatch on registered functions based on `query` type"""
56
56
  raise NotImplementedError(f"no paginate_query registered for type {type(query)!r}")
57
57
 
58
58
 
fastapi_sqla/sqla.py CHANGED
@@ -24,7 +24,7 @@ except ImportError:
24
24
  DeclarativeBase = declarative_base() # type: ignore
25
25
 
26
26
  try:
27
- from sqlmodel import Session as SqlaSession # type: ignore # noqa
27
+ from sqlmodel import Session as SqlaSession # type: ignore
28
28
 
29
29
  except ImportError:
30
30
  pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastapi-sqla
3
- Version: 3.1.2
3
+ Version: 3.3.0
4
4
  Summary: SQLAlchemy extension for FastAPI with support for pagination, asyncio, SQLModel, and pytest, ready for production.
5
5
  Home-page: https://github.com/dialoguemd/fastapi-sqla
6
6
  License: MIT
@@ -22,6 +22,7 @@ Classifier: Programming Language :: Python :: 3
22
22
  Classifier: Programming Language :: Python :: 3.9
23
23
  Classifier: Programming Language :: Python :: 3.10
24
24
  Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
25
26
  Classifier: Programming Language :: Python :: 3 :: Only
26
27
  Classifier: Programming Language :: SQL
27
28
  Classifier: Topic :: Internet
@@ -40,20 +41,19 @@ Requires-Dist: Faker (>=14.2.0,<15.0.0) ; extra == "tests"
40
41
  Requires-Dist: alembic (>=1.4.3,<2.0.0) ; extra == "tests"
41
42
  Requires-Dist: asgi_lifespan (>=1.0.1,<2.0.0) ; extra == "tests"
42
43
  Requires-Dist: asyncpg (>=0.28.0,<0.29.0) ; extra == "asyncpg"
43
- Requires-Dist: black (>=22.8.0,<23.0.0) ; extra == "tests"
44
44
  Requires-Dist: boto3 (>=1.24.74,<2.0.0) ; extra == "aws-rds-iam"
45
+ Requires-Dist: deprecated (>=1.2)
45
46
  Requires-Dist: fastapi (>=0.95.1)
46
- Requires-Dist: greenlet (>=1.1.3,<2.0.0) ; extra == "tests"
47
+ Requires-Dist: greenlet (>=3.0.3,<4.0.0) ; extra == "tests"
47
48
  Requires-Dist: httpx (>=0.23.0,<0.24.0) ; extra == "tests"
48
- Requires-Dist: isort (>=5.5.3,<6.0.0) ; extra == "tests"
49
49
  Requires-Dist: mypy[tests] (>=1.0.0,<2.0.0) ; extra == "tests"
50
50
  Requires-Dist: pdbpp (>=0.10.2,<0.11.0) ; extra == "tests"
51
51
  Requires-Dist: psycopg2 (>=2.8.6,<3.0.0) ; extra == "tests"
52
52
  Requires-Dist: pydantic (>=1)
53
- Requires-Dist: pylama (>=8.4.1,<9.0.0) ; extra == "tests"
54
53
  Requires-Dist: pytest (>=7.2.1,<8.0.0) ; extra == "tests"
55
54
  Requires-Dist: pytest-asyncio (>=0.19.0,<0.20.0) ; extra == "tests"
56
55
  Requires-Dist: pytest-cov (>=2.10.1,<3.0.0) ; extra == "tests"
56
+ Requires-Dist: ruff (>=0.4.5,<0.5.0) ; extra == "tests"
57
57
  Requires-Dist: sqlalchemy (>=1.3)
58
58
  Requires-Dist: sqlmodel (>=0.0.14,<0.0.15) ; extra == "sqlmodel"
59
59
  Requires-Dist: structlog (>=20)
@@ -90,15 +90,22 @@ unique `email`:
90
90
 
91
91
  ```python
92
92
  # main.py
93
+ from contextlib import asynccontextmanager
93
94
  from fastapi import FastAPI, HTTPException
94
- from fastapi_sqla import Base, Item, Page, Paginate, Session, setup
95
+ from fastapi_sqla import Base, Item, Page, Paginate, Session, setup_middlewares, startup
95
96
  from pydantic import BaseModel, EmailStr
96
97
  from sqlalchemy import select
97
98
  from sqlalchemy.exc import IntegrityError
98
99
 
99
- app = FastAPI()
100
100
 
101
- setup(app)
101
+ @asynccontextmanager
102
+ async def lifespan(app: FastAPI):
103
+ await startup()
104
+ yield
105
+
106
+
107
+ app = FastAPI(lifespan=lifespan)
108
+ setup_middlewares(app)
102
109
 
103
110
 
104
111
  class User(Base):
@@ -203,7 +210,23 @@ And define the environment variable `sqlalchemy_url` with `postgres+asyncpg` sch
203
210
  export sqlalchemy_url=postgresql+asyncpg://postgres@localhost
204
211
  ```
205
212
 
206
- ## Setup the app:
213
+ ## Setup the app AsyncContextManager (recommended):
214
+
215
+ ```python
216
+ import fastapi_sqla
217
+ from fastapi import FastAPI
218
+
219
+ @asynccontextmanager
220
+ async def lifespan(app: FastAPI):
221
+ await fastapi_sqla.startup()
222
+ yield
223
+
224
+
225
+ app = FastAPI(lifespan=lifespan)
226
+ fastapi_sqla.setup_middlewares(app)
227
+ ```
228
+
229
+ ## Setup the app using startup/shutdown events (deprecated):
207
230
 
208
231
  ```python
209
232
  import fastapi_sqla
@@ -0,0 +1,16 @@
1
+ fastapi_sqla/__init__.py,sha256=RRkwo9xZzidQ-k3BRXfqT0jtWm8d08w94XuOLteFCdU,1221
2
+ fastapi_sqla/_pytest_plugin.py,sha256=IQUlj-O874Sfuth254LBrEBGCrwH3rNHST9OMZl2pIk,5411
3
+ fastapi_sqla/async_pagination.py,sha256=3DHGUjvrpkbWMIc_BEX4GvM-_PTcn62K9z48ucTJlH0,3164
4
+ fastapi_sqla/async_sqla.py,sha256=7SXRH3DMsQvpjCQdvCBEjQhDZ4-cPAg175MlgNVBnCg,5888
5
+ fastapi_sqla/aws_aurora_support.py,sha256=4dxLKOqDccgLwFqlz81L6f4HzrOXMZkY7Zuf4t_310U,838
6
+ fastapi_sqla/aws_rds_iam_support.py,sha256=Uw-XaiwShMMWYKCvlSqXoxvtKMblCAvbCZ1m6BYVpJk,1257
7
+ fastapi_sqla/base.py,sha256=8XHIKO8sBOmnRvCsOYRWhg5Y-XYqobM5DypeIMvJTFs,2501
8
+ fastapi_sqla/models.py,sha256=-B1xwINpTc9rEQd3KYHEC1s5s7jdVQkJ6Gy6xpmT13c,1108
9
+ fastapi_sqla/pagination.py,sha256=1gfIGcmt1OFspbRgtJ8AZOZdFd14DGRc4FkDgyh5bJ8,4517
10
+ fastapi_sqla/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ fastapi_sqla/sqla.py,sha256=irHuZaun027o9WJrdcZPavCN2vXNHupCWYhU5Dx-AqE,6348
12
+ fastapi_sqla-3.3.0.dist-info/LICENSE,sha256=8G0-nWLqi3xRYRrtRlTE8n1mkYJcnCRoZGUhv6ZE29c,1064
13
+ fastapi_sqla-3.3.0.dist-info/METADATA,sha256=sNlfIYlzk2w8fmVxJh8jsOinZLJHrmOgWMLCZi4DV4o,21391
14
+ fastapi_sqla-3.3.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
15
+ fastapi_sqla-3.3.0.dist-info/entry_points.txt,sha256=haa0EueKcRo8-AlJTpHBMn08wMBiULNGA53nkvaDWj0,53
16
+ fastapi_sqla-3.3.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.6.1
2
+ Generator: poetry-core 1.9.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,16 +0,0 @@
1
- fastapi_sqla/__init__.py,sha256=G9bKR6L9EnLgzelE_BLnHgc1cOm0Yu0wMzwLAdyA8iE,1153
2
- fastapi_sqla/_pytest_plugin.py,sha256=bjPzOuwk32Zo4hoOa_bGjTGhtHGPImh3RyiORqz-J84,5430
3
- fastapi_sqla/async_pagination.py,sha256=jYeZYtIi7mssM3MfwobOoaPYNZF0BE1EmCK8CqFnwOg,3164
4
- fastapi_sqla/async_sqla.py,sha256=7SXRH3DMsQvpjCQdvCBEjQhDZ4-cPAg175MlgNVBnCg,5888
5
- fastapi_sqla/aws_aurora_support.py,sha256=4dxLKOqDccgLwFqlz81L6f4HzrOXMZkY7Zuf4t_310U,838
6
- fastapi_sqla/aws_rds_iam_support.py,sha256=YSJNhrxmhGN-GVk9PLMTmQSWTKZBvuorKkhc_XaoL44,1189
7
- fastapi_sqla/base.py,sha256=0X7Gbt49rBHPiSFmNy5S2PT0dA4UBNnwrAesYSkaHBc,1606
8
- fastapi_sqla/models.py,sha256=fesW7BqkwOA4iC345dbybzcV8Kz4-kLwREo38oqy_7A,1108
9
- fastapi_sqla/pagination.py,sha256=IjbKFyUHly8jHyOO4pnyPK4RE_cFRDY03OOZeZEm3cY,4513
10
- fastapi_sqla/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- fastapi_sqla/sqla.py,sha256=lOikCu_BjGQYfbbtcM59ZjwTL-66cM9L_yIbCEQasAQ,6356
12
- fastapi_sqla-3.1.2.dist-info/LICENSE,sha256=8G0-nWLqi3xRYRrtRlTE8n1mkYJcnCRoZGUhv6ZE29c,1064
13
- fastapi_sqla-3.1.2.dist-info/METADATA,sha256=xl5jfdozvDDEJGHW0fe9bFm_ITasdlzYb3NThMDveNk,20915
14
- fastapi_sqla-3.1.2.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
15
- fastapi_sqla-3.1.2.dist-info/entry_points.txt,sha256=haa0EueKcRo8-AlJTpHBMn08wMBiULNGA53nkvaDWj0,53
16
- fastapi_sqla-3.1.2.dist-info/RECORD,,