fastapi-sqla 3.2.1__tar.gz → 3.3.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastapi-sqla
3
- Version: 3.2.1
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
@@ -42,6 +42,7 @@ Requires-Dist: alembic (>=1.4.3,<2.0.0) ; extra == "tests"
42
42
  Requires-Dist: asgi_lifespan (>=1.0.1,<2.0.0) ; extra == "tests"
43
43
  Requires-Dist: asyncpg (>=0.28.0,<0.29.0) ; extra == "asyncpg"
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
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"
@@ -89,15 +90,22 @@ unique `email`:
89
90
 
90
91
  ```python
91
92
  # main.py
93
+ from contextlib import asynccontextmanager
92
94
  from fastapi import FastAPI, HTTPException
93
- from fastapi_sqla import Base, Item, Page, Paginate, Session, setup
95
+ from fastapi_sqla import Base, Item, Page, Paginate, Session, setup_middlewares, startup
94
96
  from pydantic import BaseModel, EmailStr
95
97
  from sqlalchemy import select
96
98
  from sqlalchemy.exc import IntegrityError
97
99
 
98
- app = FastAPI()
99
100
 
100
- 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)
101
109
 
102
110
 
103
111
  class User(Base):
@@ -202,7 +210,23 @@ And define the environment variable `sqlalchemy_url` with `postgres+asyncpg` sch
202
210
  export sqlalchemy_url=postgresql+asyncpg://postgres@localhost
203
211
  ```
204
212
 
205
- ## 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):
206
230
 
207
231
  ```python
208
232
  import fastapi_sqla
@@ -27,15 +27,22 @@ unique `email`:
27
27
 
28
28
  ```python
29
29
  # main.py
30
+ from contextlib import asynccontextmanager
30
31
  from fastapi import FastAPI, HTTPException
31
- from fastapi_sqla import Base, Item, Page, Paginate, Session, setup
32
+ from fastapi_sqla import Base, Item, Page, Paginate, Session, setup_middlewares, startup
32
33
  from pydantic import BaseModel, EmailStr
33
34
  from sqlalchemy import select
34
35
  from sqlalchemy.exc import IntegrityError
35
36
 
36
- app = FastAPI()
37
37
 
38
- setup(app)
38
+ @asynccontextmanager
39
+ async def lifespan(app: FastAPI):
40
+ await startup()
41
+ yield
42
+
43
+
44
+ app = FastAPI(lifespan=lifespan)
45
+ setup_middlewares(app)
39
46
 
40
47
 
41
48
  class User(Base):
@@ -140,7 +147,23 @@ And define the environment variable `sqlalchemy_url` with `postgres+asyncpg` sch
140
147
  export sqlalchemy_url=postgresql+asyncpg://postgres@localhost
141
148
  ```
142
149
 
143
- ## Setup the app:
150
+ ## Setup the app AsyncContextManager (recommended):
151
+
152
+ ```python
153
+ import fastapi_sqla
154
+ from fastapi import FastAPI
155
+
156
+ @asynccontextmanager
157
+ async def lifespan(app: FastAPI):
158
+ await fastapi_sqla.startup()
159
+ yield
160
+
161
+
162
+ app = FastAPI(lifespan=lifespan)
163
+ fastapi_sqla.setup_middlewares(app)
164
+ ```
165
+
166
+ ## Setup the app using startup/shutdown events (deprecated):
144
167
 
145
168
  ```python
146
169
  import fastapi_sqla
@@ -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
 
@@ -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}
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "fastapi-sqla"
3
- version = "3.2.1"
3
+ version = "3.3.0"
4
4
  description = "SQLAlchemy extension for FastAPI with support for pagination, asyncio, SQLModel, and pytest, ready for production."
5
5
  authors = [
6
6
  "Hadrien David <hadrien.david@dialogue.co>",
@@ -43,22 +43,23 @@ fastapi = ">=0.95.1"
43
43
  pydantic = ">=1"
44
44
  sqlalchemy = ">=1.3"
45
45
  structlog = ">=20"
46
-
47
- alembic = { version = "^1.4.3", optional = true}
48
- asgi_lifespan = { version = "^1.0.1", optional = true}
49
- asyncpg = {version = "^0.28.0", optional = true}
50
- Faker = {version = "^14.2.0", optional = true}
51
- httpx = {version = "^0.23.0", optional = true}
52
- pdbpp = { version = "^0.10.2", optional = true}
53
- psycopg2 = { version = "^2.8.6", optional = true}
54
- pytest = {version = "^7.2.1", optional = true}
55
- pytest-asyncio = {version = "^0.19.0", optional = true}
56
- pytest-cov = { version = "^2.10.1", optional = true}
57
- ruff = {version = "^0.4.5", optional = true}
58
- tox = {version = "^3.26.0", optional = true}
59
- boto3 = {version = "^1.24.74", optional = true}
60
- greenlet = {version = "^3.0.3", optional = true}
61
- mypy = {version = "^1.0.0", extras = ["tests"], optional = true}
46
+ deprecated = ">=1.2"
47
+
48
+ alembic = { version = "^1.4.3", optional = true }
49
+ asgi_lifespan = { version = "^1.0.1", optional = true }
50
+ asyncpg = { version = "^0.28.0", optional = true }
51
+ Faker = { version = "^14.2.0", optional = true }
52
+ httpx = { version = "^0.23.0", optional = true }
53
+ pdbpp = { version = "^0.10.2", optional = true }
54
+ psycopg2 = { version = "^2.8.6", optional = true }
55
+ pytest = { version = "^7.2.1", optional = true }
56
+ pytest-asyncio = { version = "^0.19.0", optional = true }
57
+ pytest-cov = { version = "^2.10.1", optional = true }
58
+ ruff = { version = "^0.4.5", optional = true }
59
+ tox = { version = "^3.26.0", optional = true }
60
+ boto3 = { version = "^1.24.74", optional = true }
61
+ greenlet = { version = "^3.0.3", optional = true }
62
+ mypy = { version = "^1.0.0", extras = ["tests"], optional = true }
62
63
  sqlmodel = { version = "^0.0.14", optional = true }
63
64
 
64
65
  [tool.poetry.extras]
@@ -102,58 +103,58 @@ target-version = "py39"
102
103
 
103
104
  [tool.ruff.lint]
104
105
  select = [
105
- "E", # pycodestyle
106
- "W", # pycodestyle warnings
107
- "F", # pyflakes
108
- "I", # isort
109
- "N", # pep8-naming
110
- "D", # pydocstyle
111
- "UP", # pyupgrade
112
- "ASYNC", # flake8-async
113
- "S", # flake8-bandit
114
- "B", # flake8-bugbear
115
- "C4", # flake8-comprehensions
116
- "SIM", # flake8-simplify
117
- "TD", # flake8-todos
118
- "ERA", # eradicate
119
- "PL", # pylint
120
- "RUF" # ruff
106
+ "E", # pycodestyle
107
+ "W", # pycodestyle warnings
108
+ "F", # pyflakes
109
+ "I", # isort
110
+ "N", # pep8-naming
111
+ "D", # pydocstyle
112
+ "UP", # pyupgrade
113
+ "ASYNC", # flake8-async
114
+ "S", # flake8-bandit
115
+ "B", # flake8-bugbear
116
+ "C4", # flake8-comprehensions
117
+ "SIM", # flake8-simplify
118
+ "TD", # flake8-todos
119
+ "ERA", # eradicate
120
+ "PL", # pylint
121
+ "RUF", # ruff
121
122
  ]
122
123
 
123
124
  # Ignore some pydocstyle rules that Google convention enables
124
125
  ignore = [
125
- "D100",
126
- "D101",
127
- "D102",
128
- "D103",
129
- "D104",
130
- "D105",
131
- "D106",
132
- "D107",
133
- "D212",
134
- "D415",
135
- "B008", # Enable using functions in default function args. Easier to work with FastAPI dependencies that way
136
- "C408", # Enable using dict/list/tuple
137
- "PLR0911", # Disable max number of return
138
- "PLR0912", # Disable max number of branches
139
- "PLR0913", # Disable max number of args
140
- "PLR0915", # Disable max number of statements
141
- "PLR2004", # Enable magic values
142
- "SIM105", # Allow using try - except - pass
143
- "TD001", # Enable FIXMEs
144
- "TD002", # Enable TODOs without author
145
- "TD003", # Enable TODOs without issue link
146
- "N802", # FastAPI dependency conventions is title cased
147
- "N803", # Same as N802
148
- "N806", # Same as N802
126
+ "D100",
127
+ "D101",
128
+ "D102",
129
+ "D103",
130
+ "D104",
131
+ "D105",
132
+ "D106",
133
+ "D107",
134
+ "D212",
135
+ "D415",
136
+ "B008", # Enable using functions in default function args. Easier to work with FastAPI dependencies that way
137
+ "C408", # Enable using dict/list/tuple
138
+ "PLR0911", # Disable max number of return
139
+ "PLR0912", # Disable max number of branches
140
+ "PLR0913", # Disable max number of args
141
+ "PLR0915", # Disable max number of statements
142
+ "PLR2004", # Enable magic values
143
+ "SIM105", # Allow using try - except - pass
144
+ "TD001", # Enable FIXMEs
145
+ "TD002", # Enable TODOs without author
146
+ "TD003", # Enable TODOs without issue link
147
+ "N802", # FastAPI dependency conventions is title cased
148
+ "N803", # Same as N802
149
+ "N806", # Same as N802
149
150
  ]
150
151
 
151
152
  [tool.ruff.lint.extend-per-file-ignores]
152
153
  "tests/*" = [
153
- "S101", # Enable assert
154
- "S105", # Disable passwords check
155
- "S106", # Disable passwords check
156
- "S608", # Allow SQL string construction
154
+ "S101", # Enable assert
155
+ "S105", # Disable passwords check
156
+ "S106", # Disable passwords check
157
+ "S608", # Allow SQL string construction
157
158
  ]
158
159
 
159
160
  [tool.ruff.lint.pydocstyle]
@@ -172,19 +173,14 @@ addopts = """
172
173
  """
173
174
 
174
175
  # https://nedbatchelder.com/blog/201810/why_warnings_is_mysterious.html
175
- filterwarnings = [
176
- "error:.*removed in version 2.0.*:",
177
- ]
176
+ filterwarnings = ["error:.*removed in version 2.0.*:"]
178
177
 
179
178
  [tool.pytest-watch.run]
180
179
  ext = ".py, .yaml, .cfg"
181
180
 
182
181
  [tool.coverage.run]
183
182
  branch = true
184
- omit = [
185
- "tests/*",
186
- ".venv/*"
187
- ]
183
+ omit = ["tests/*", ".venv/*"]
188
184
  concurrency = ["thread", "greenlet"]
189
185
 
190
186
  [tool.coverage.report]
@@ -216,5 +212,8 @@ commands = pytest -vv --cov={envsitepackagesdir}/fastapi_sqla --cov-report xml -
216
212
 
217
213
  [tool.mypy]
218
214
  exclude = ["tests"]
215
+ plugins = ["sqlalchemy.ext.mypy.plugin"]
216
+
217
+ [[tool.mypy.overrides]]
218
+ module = ["asyncpg", "boto3", "deprecated"]
219
219
  ignore_missing_imports = true
220
- plugins = "sqlalchemy.ext.mypy.plugin"
File without changes