fastapi-sqla 3.4.7__tar.gz → 3.5.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.
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/PKG-INFO +4 -3
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/_pytest_plugin.py +58 -43
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/async_sqla.py +30 -14
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/base.py +3 -2
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/sqla.py +17 -10
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/pyproject.toml +12 -12
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/LICENSE +0 -0
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/README.md +0 -0
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/__init__.py +0 -0
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/async_pagination.py +0 -0
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/aws_aurora_support.py +0 -0
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/aws_rds_iam_support.py +0 -0
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/models.py +0 -0
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/pagination.py +0 -0
- {fastapi_sqla-3.4.7 → fastapi_sqla-3.5.0}/fastapi_sqla/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fastapi-sqla
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.5.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
|
|
@@ -23,6 +23,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.10
|
|
24
24
|
Classifier: Programming Language :: Python :: 3.11
|
|
25
25
|
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
27
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
27
28
|
Classifier: Programming Language :: SQL
|
|
28
29
|
Classifier: Topic :: Internet
|
|
@@ -46,8 +47,8 @@ Requires-Dist: fastapi (>=0.95.1,<0.116)
|
|
|
46
47
|
Requires-Dist: psycopg2 (>=2.8.6,<3) ; extra == "psycopg2"
|
|
47
48
|
Requires-Dist: pydantic (>=1,<3)
|
|
48
49
|
Requires-Dist: sqlalchemy (>=1.3,<3)
|
|
49
|
-
Requires-Dist: sqlmodel (>=0.0.14,<0.0.
|
|
50
|
-
Requires-Dist: structlog (>=20,<
|
|
50
|
+
Requires-Dist: sqlmodel (>=0.0.14,<0.0.25) ; extra == "sqlmodel"
|
|
51
|
+
Requires-Dist: structlog (>=20,<26)
|
|
51
52
|
Project-URL: Repository, https://github.com/dialoguemd/fastapi-sqla
|
|
52
53
|
Description-Content-Type: text/markdown
|
|
53
54
|
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from collections.abc import AsyncGenerator, Generator
|
|
2
3
|
from unittest.mock import patch
|
|
3
4
|
from urllib.parse import urlsplit, urlunsplit
|
|
4
5
|
|
|
5
6
|
from alembic import command
|
|
6
7
|
from alembic.config import Config
|
|
7
|
-
from pytest import fixture
|
|
8
|
+
from pytest import FixtureRequest, fixture
|
|
8
9
|
from sqlalchemy import create_engine, text
|
|
9
|
-
from sqlalchemy.
|
|
10
|
+
from sqlalchemy.engine import Connection, Engine
|
|
11
|
+
from sqlalchemy.orm.session import Session, sessionmaker
|
|
10
12
|
|
|
11
13
|
try:
|
|
12
14
|
import asyncpg # noqa
|
|
13
|
-
from sqlalchemy.ext.asyncio import
|
|
15
|
+
from sqlalchemy.ext.asyncio import (
|
|
16
|
+
create_async_engine,
|
|
17
|
+
AsyncEngine,
|
|
18
|
+
AsyncConnection,
|
|
19
|
+
AsyncSession,
|
|
20
|
+
)
|
|
14
21
|
|
|
15
22
|
asyncio_support = True
|
|
16
23
|
except ImportError:
|
|
@@ -22,7 +29,7 @@ def pytest_configure(config):
|
|
|
22
29
|
|
|
23
30
|
|
|
24
31
|
@fixture(scope="session")
|
|
25
|
-
def db_host():
|
|
32
|
+
def db_host() -> str:
|
|
26
33
|
"""Default db host used by depending fixtures.
|
|
27
34
|
|
|
28
35
|
When CI key is set in environment variables, it uses `postgres` as host name else,
|
|
@@ -32,7 +39,7 @@ def db_host():
|
|
|
32
39
|
|
|
33
40
|
|
|
34
41
|
@fixture(scope="session")
|
|
35
|
-
def db_user():
|
|
42
|
+
def db_user() -> str:
|
|
36
43
|
"""Default db user used by depending fixtures.
|
|
37
44
|
|
|
38
45
|
postgres
|
|
@@ -41,7 +48,7 @@ def db_user():
|
|
|
41
48
|
|
|
42
49
|
|
|
43
50
|
@fixture(scope="session")
|
|
44
|
-
def db_url(db_host, db_user):
|
|
51
|
+
def db_url(db_host: str, db_user: str) -> str:
|
|
45
52
|
"""Default db url used by depending fixtures.
|
|
46
53
|
|
|
47
54
|
db url example postgresql://{db_user}@{db_host}/postgres
|
|
@@ -50,24 +57,24 @@ def db_url(db_host, db_user):
|
|
|
50
57
|
|
|
51
58
|
|
|
52
59
|
@fixture(scope="session")
|
|
53
|
-
def engine(db_url):
|
|
60
|
+
def engine(db_url: str) -> Engine:
|
|
54
61
|
return create_engine(db_url)
|
|
55
62
|
|
|
56
63
|
|
|
57
64
|
@fixture(scope="session")
|
|
58
|
-
def sqla_connection(engine):
|
|
65
|
+
def sqla_connection(engine: Engine) -> Generator[Connection]:
|
|
59
66
|
with engine.connect() as connection:
|
|
60
67
|
yield connection
|
|
61
68
|
|
|
62
69
|
|
|
63
70
|
@fixture(scope="session")
|
|
64
|
-
def alembic_ini_path(): # pragma: no cover
|
|
71
|
+
def alembic_ini_path() -> str: # pragma: no cover
|
|
65
72
|
"""Path for alembic.ini file, defaults to `./alembic.ini`."""
|
|
66
73
|
return "./alembic.ini"
|
|
67
74
|
|
|
68
75
|
|
|
69
76
|
@fixture(scope="session")
|
|
70
|
-
def db_migration(db_url, sqla_connection, alembic_ini_path):
|
|
77
|
+
def db_migration(db_url: str, sqla_connection: Connection, alembic_ini_path: str):
|
|
71
78
|
"""Run alembic upgrade at test session setup and downgrade at tear down.
|
|
72
79
|
|
|
73
80
|
Override fixture `alembic_ini_path` to change path of `alembic.ini` file.
|
|
@@ -94,54 +101,52 @@ def sqla_modules():
|
|
|
94
101
|
|
|
95
102
|
|
|
96
103
|
@fixture
|
|
97
|
-
def sqla_reflection(sqla_modules, sqla_connection):
|
|
104
|
+
def sqla_reflection(sqla_modules, sqla_connection: Connection):
|
|
98
105
|
import fastapi_sqla
|
|
99
106
|
|
|
100
|
-
fastapi_sqla.Base.metadata.bind = sqla_connection
|
|
107
|
+
fastapi_sqla.Base.metadata.bind = sqla_connection # type: ignore
|
|
101
108
|
fastapi_sqla.Base.prepare(sqla_connection.engine)
|
|
102
109
|
|
|
103
110
|
|
|
104
111
|
@fixture
|
|
105
|
-
def
|
|
112
|
+
def patch_new_engine(request: FixtureRequest, sqla_connection: Connection):
|
|
106
113
|
"""So that all DB operations are never written to db for real."""
|
|
107
114
|
if "dont_patch_engines" in request.keywords:
|
|
108
115
|
yield
|
|
109
116
|
else:
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
engine_from_config.return_value = sqla_connection
|
|
114
|
-
yield
|
|
117
|
+
with sqla_connection.begin() as transaction:
|
|
118
|
+
with patch("fastapi_sqla.sqla.new_engine", return_value=sqla_connection):
|
|
119
|
+
yield
|
|
115
120
|
|
|
116
|
-
|
|
121
|
+
transaction.rollback()
|
|
117
122
|
|
|
118
123
|
|
|
119
124
|
@fixture
|
|
120
|
-
def session_factory(
|
|
121
|
-
|
|
125
|
+
def session_factory(
|
|
126
|
+
sqla_connection: Connection, sqla_reflection, patch_new_engine
|
|
127
|
+
) -> sessionmaker:
|
|
128
|
+
return sessionmaker(bind=sqla_connection)
|
|
122
129
|
|
|
123
130
|
|
|
124
131
|
@fixture
|
|
125
|
-
def session(
|
|
126
|
-
session_factory, sqla_connection, sqla_reflection, patch_engine_from_config
|
|
127
|
-
):
|
|
132
|
+
def session(session_factory: sessionmaker) -> Generator[Session]:
|
|
128
133
|
"""Sqla session to use when creating db fixtures.
|
|
129
134
|
|
|
130
135
|
While it does not write any record in DB, the application will still be able to
|
|
131
136
|
access any record committed with that session.
|
|
132
137
|
"""
|
|
133
|
-
session = session_factory(
|
|
138
|
+
session: Session = session_factory()
|
|
134
139
|
yield session
|
|
135
140
|
session.close()
|
|
136
141
|
|
|
137
142
|
|
|
138
|
-
def format_async_async_sqlalchemy_url(url):
|
|
143
|
+
def format_async_async_sqlalchemy_url(url: str) -> str:
|
|
139
144
|
scheme, location, path, query, fragment = urlsplit(url)
|
|
140
145
|
return urlunsplit([f"{scheme}+asyncpg", location, path, query, fragment])
|
|
141
146
|
|
|
142
147
|
|
|
143
148
|
@fixture(scope="session")
|
|
144
|
-
def async_sqlalchemy_url(db_url):
|
|
149
|
+
def async_sqlalchemy_url(db_url: str) -> str:
|
|
145
150
|
"""Default async db url.
|
|
146
151
|
|
|
147
152
|
It is the same as `db_url` with `postgresql+asyncpg://` as scheme.
|
|
@@ -152,46 +157,56 @@ def async_sqlalchemy_url(db_url):
|
|
|
152
157
|
if asyncio_support:
|
|
153
158
|
|
|
154
159
|
@fixture
|
|
155
|
-
def async_engine(async_sqlalchemy_url):
|
|
160
|
+
def async_engine(async_sqlalchemy_url: str) -> AsyncEngine:
|
|
156
161
|
return create_async_engine(async_sqlalchemy_url)
|
|
157
162
|
|
|
158
163
|
@fixture
|
|
159
|
-
async def async_sqla_connection(
|
|
164
|
+
async def async_sqla_connection(
|
|
165
|
+
async_engine: AsyncEngine,
|
|
166
|
+
) -> AsyncGenerator[AsyncConnection]:
|
|
160
167
|
async with async_engine.connect() as connection:
|
|
161
168
|
yield connection
|
|
162
169
|
|
|
163
170
|
@fixture
|
|
164
|
-
async def
|
|
171
|
+
async def patch_new_async_engine(
|
|
172
|
+
request: FixtureRequest, async_sqla_connection: AsyncConnection
|
|
173
|
+
):
|
|
165
174
|
"""So that all async DB operations are never written to db for real."""
|
|
166
175
|
if "dont_patch_engines" in request.keywords:
|
|
167
176
|
yield
|
|
168
177
|
else:
|
|
169
178
|
async with async_sqla_connection.begin() as transaction:
|
|
170
|
-
with patch(
|
|
171
|
-
|
|
179
|
+
with patch(
|
|
180
|
+
"fastapi_sqla.async_sqla.new_async_engine",
|
|
181
|
+
return_value=async_sqla_connection,
|
|
182
|
+
):
|
|
172
183
|
yield
|
|
173
184
|
|
|
174
185
|
await transaction.rollback()
|
|
175
186
|
|
|
176
187
|
@fixture
|
|
177
|
-
async def async_sqla_reflection(
|
|
188
|
+
async def async_sqla_reflection(
|
|
189
|
+
sqla_modules, async_sqla_connection: AsyncConnection
|
|
190
|
+
):
|
|
178
191
|
from fastapi_sqla import Base
|
|
179
192
|
|
|
180
193
|
await async_sqla_connection.run_sync(lambda conn: Base.prepare(conn.engine))
|
|
181
194
|
|
|
182
195
|
@fixture
|
|
183
|
-
def async_session_factory(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
196
|
+
def async_session_factory(
|
|
197
|
+
async_sqla_connection: AsyncConnection,
|
|
198
|
+
async_sqla_reflection,
|
|
199
|
+
patch_new_async_engine,
|
|
200
|
+
) -> sessionmaker:
|
|
201
|
+
# TODO: Use async_sessionmaker once only supporting 2.x+
|
|
202
|
+
return sessionmaker(
|
|
203
|
+
bind=async_sqla_connection, expire_on_commit=False, class_=AsyncSession
|
|
204
|
+
) # type: ignore
|
|
187
205
|
|
|
188
206
|
@fixture
|
|
189
207
|
async def async_session(
|
|
190
|
-
async_session_factory,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
patch_new_engine,
|
|
194
|
-
):
|
|
195
|
-
session = async_session_factory(bind=async_sqla_connection)
|
|
208
|
+
async_session_factory: sessionmaker,
|
|
209
|
+
) -> AsyncGenerator[AsyncSession]:
|
|
210
|
+
session: AsyncSession = async_session_factory()
|
|
196
211
|
yield session
|
|
197
212
|
await session.close()
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
+
import os
|
|
1
2
|
from collections.abc import AsyncGenerator
|
|
2
3
|
from contextlib import asynccontextmanager
|
|
3
|
-
from typing import Annotated
|
|
4
|
+
from typing import Annotated, Union
|
|
4
5
|
|
|
5
6
|
import structlog
|
|
6
7
|
from fastapi import Depends, Request, Response
|
|
7
8
|
from fastapi.responses import PlainTextResponse
|
|
8
9
|
from sqlalchemy import text
|
|
9
|
-
from sqlalchemy.ext.asyncio import
|
|
10
|
+
from sqlalchemy.ext.asyncio import (
|
|
11
|
+
AsyncConnection,
|
|
12
|
+
AsyncEngine,
|
|
13
|
+
async_engine_from_config,
|
|
14
|
+
)
|
|
10
15
|
from sqlalchemy.ext.asyncio import AsyncSession as SqlaAsyncSession
|
|
11
16
|
from sqlalchemy.orm.session import sessionmaker
|
|
12
17
|
from starlette.types import ASGIApp, Message, Receive, Scope, Send
|
|
13
18
|
|
|
14
19
|
from fastapi_sqla import aws_aurora_support, aws_rds_iam_support
|
|
15
|
-
from fastapi_sqla.sqla import _DEFAULT_SESSION_KEY, Base,
|
|
20
|
+
from fastapi_sqla.sqla import _DEFAULT_SESSION_KEY, Base, get_envvar_prefix
|
|
16
21
|
|
|
17
22
|
logger = structlog.get_logger(__name__)
|
|
18
23
|
|
|
@@ -20,19 +25,29 @@ _ASYNC_REQUEST_SESSION_KEY = "fastapi_sqla_async_session"
|
|
|
20
25
|
_async_session_factories: dict[str, sessionmaker] = {}
|
|
21
26
|
|
|
22
27
|
|
|
23
|
-
def new_async_engine(
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
def new_async_engine(
|
|
29
|
+
key: str = _DEFAULT_SESSION_KEY,
|
|
30
|
+
) -> Union[AsyncEngine, AsyncConnection]:
|
|
31
|
+
envvar_prefix = get_envvar_prefix(key)
|
|
32
|
+
lowercase_environ = {k.lower(): v for k, v in os.environ.items()}
|
|
33
|
+
lowercase_environ.pop(f"{envvar_prefix}warn_20", None)
|
|
34
|
+
return async_engine_from_config(lowercase_environ, prefix=envvar_prefix)
|
|
26
35
|
|
|
27
36
|
|
|
28
37
|
async def startup(key: str = _DEFAULT_SESSION_KEY):
|
|
29
|
-
|
|
30
|
-
aws_rds_iam_support.setup(
|
|
31
|
-
aws_aurora_support.setup(
|
|
38
|
+
engine_or_connection = new_async_engine(key)
|
|
39
|
+
aws_rds_iam_support.setup(engine_or_connection.sync_engine)
|
|
40
|
+
aws_aurora_support.setup(engine_or_connection.sync_engine)
|
|
41
|
+
|
|
42
|
+
async_engine = (
|
|
43
|
+
engine_or_connection
|
|
44
|
+
if isinstance(engine_or_connection, AsyncEngine)
|
|
45
|
+
else engine_or_connection.engine
|
|
46
|
+
)
|
|
32
47
|
|
|
33
48
|
# Fail early
|
|
34
49
|
try:
|
|
35
|
-
async with
|
|
50
|
+
async with async_engine.connect() as connection:
|
|
36
51
|
await connection.execute(text("select 'ok'"))
|
|
37
52
|
except Exception:
|
|
38
53
|
logger.critical(
|
|
@@ -41,14 +56,15 @@ async def startup(key: str = _DEFAULT_SESSION_KEY):
|
|
|
41
56
|
)
|
|
42
57
|
raise
|
|
43
58
|
|
|
44
|
-
async with
|
|
59
|
+
async with async_engine.connect() as connection:
|
|
45
60
|
await connection.run_sync(lambda conn: Base.prepare(conn.engine))
|
|
46
61
|
|
|
62
|
+
# TODO: Use async_sessionmaker once only supporting 2.x+
|
|
47
63
|
_async_session_factories[key] = sessionmaker(
|
|
48
|
-
class_=SqlaAsyncSession, bind=
|
|
49
|
-
)
|
|
64
|
+
class_=SqlaAsyncSession, bind=engine_or_connection, expire_on_commit=False
|
|
65
|
+
) # type: ignore
|
|
50
66
|
|
|
51
|
-
logger.info("engine startup", engine_key=key, async_engine=
|
|
67
|
+
logger.info("engine startup", engine_key=key, async_engine=engine_or_connection)
|
|
52
68
|
|
|
53
69
|
|
|
54
70
|
@asynccontextmanager
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
|
+
from typing import Union
|
|
4
5
|
|
|
5
6
|
from deprecated import deprecated
|
|
6
7
|
from fastapi import FastAPI
|
|
7
|
-
from sqlalchemy.engine import Engine
|
|
8
|
+
from sqlalchemy.engine import Connection, Engine
|
|
8
9
|
|
|
9
10
|
from fastapi_sqla import sqla
|
|
10
11
|
|
|
@@ -72,5 +73,5 @@ def _get_engine_keys() -> set[str]:
|
|
|
72
73
|
return keys
|
|
73
74
|
|
|
74
75
|
|
|
75
|
-
def _is_async_dialect(engine: Engine):
|
|
76
|
+
def _is_async_dialect(engine: Union[Engine, Connection]):
|
|
76
77
|
return engine.dialect.is_async if hasattr(engine.dialect, "is_async") else False
|
|
@@ -2,14 +2,14 @@ import asyncio
|
|
|
2
2
|
import os
|
|
3
3
|
from collections.abc import Generator
|
|
4
4
|
from contextlib import contextmanager
|
|
5
|
-
from typing import Annotated
|
|
5
|
+
from typing import Annotated, Union
|
|
6
6
|
|
|
7
7
|
import structlog
|
|
8
8
|
from fastapi import Depends, Request, Response
|
|
9
9
|
from fastapi.concurrency import contextmanager_in_threadpool
|
|
10
10
|
from fastapi.responses import PlainTextResponse
|
|
11
11
|
from sqlalchemy import engine_from_config, text
|
|
12
|
-
from sqlalchemy.engine import Engine
|
|
12
|
+
from sqlalchemy.engine import Connection, Engine
|
|
13
13
|
from sqlalchemy.ext.declarative import DeferredReflection
|
|
14
14
|
from sqlalchemy.orm.session import Session as SqlaSession
|
|
15
15
|
from sqlalchemy.orm.session import sessionmaker
|
|
@@ -42,24 +42,29 @@ class Base(DeclarativeBase, DeferredReflection):
|
|
|
42
42
|
__abstract__ = True
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def
|
|
45
|
+
def get_envvar_prefix(key: str) -> str:
|
|
46
46
|
envvar_prefix = "sqlalchemy_"
|
|
47
47
|
if key != _DEFAULT_SESSION_KEY:
|
|
48
48
|
envvar_prefix = f"fastapi_sqla__{key}__{envvar_prefix}"
|
|
49
49
|
|
|
50
|
+
return envvar_prefix
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def new_engine(key: str = _DEFAULT_SESSION_KEY) -> Union[Engine, Connection]:
|
|
54
|
+
envvar_prefix = get_envvar_prefix(key)
|
|
50
55
|
lowercase_environ = {k.lower(): v for k, v in os.environ.items()}
|
|
51
56
|
lowercase_environ.pop(f"{envvar_prefix}warn_20", None)
|
|
52
57
|
return engine_from_config(lowercase_environ, prefix=envvar_prefix)
|
|
53
58
|
|
|
54
59
|
|
|
55
60
|
def startup(key: str = _DEFAULT_SESSION_KEY):
|
|
56
|
-
|
|
57
|
-
aws_rds_iam_support.setup(
|
|
58
|
-
aws_aurora_support.setup(
|
|
61
|
+
engine_or_connection = new_engine(key)
|
|
62
|
+
aws_rds_iam_support.setup(engine_or_connection.engine)
|
|
63
|
+
aws_aurora_support.setup(engine_or_connection.engine)
|
|
59
64
|
|
|
60
65
|
# Fail early
|
|
61
66
|
try:
|
|
62
|
-
with engine.connect() as connection:
|
|
67
|
+
with engine_or_connection.engine.connect() as connection:
|
|
63
68
|
connection.execute(text("select 'OK'"))
|
|
64
69
|
except Exception:
|
|
65
70
|
logger.critical(
|
|
@@ -68,11 +73,13 @@ def startup(key: str = _DEFAULT_SESSION_KEY):
|
|
|
68
73
|
)
|
|
69
74
|
raise
|
|
70
75
|
|
|
71
|
-
Base.prepare(engine)
|
|
76
|
+
Base.prepare(engine_or_connection.engine)
|
|
72
77
|
|
|
73
|
-
_session_factories[key] = sessionmaker(
|
|
78
|
+
_session_factories[key] = sessionmaker(
|
|
79
|
+
bind=engine_or_connection, class_=SqlaSession
|
|
80
|
+
)
|
|
74
81
|
|
|
75
|
-
logger.info("engine startup", engine_key=key, engine=
|
|
82
|
+
logger.info("engine startup", engine_key=key, engine=engine_or_connection)
|
|
76
83
|
|
|
77
84
|
|
|
78
85
|
@contextmanager
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "fastapi-sqla"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.5.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>",
|
|
@@ -42,28 +42,28 @@ python = ">=3.9,<3.14"
|
|
|
42
42
|
fastapi = ">=0.95.1,<0.116"
|
|
43
43
|
pydantic = ">=1,<3"
|
|
44
44
|
sqlalchemy = ">=1.3,<3"
|
|
45
|
-
structlog = ">=20,<
|
|
45
|
+
structlog = ">=20,<26"
|
|
46
46
|
deprecated = ">=1.2,<2"
|
|
47
47
|
|
|
48
48
|
alembic = { version = ">=1.4.3,<2", optional = true }
|
|
49
49
|
asyncpg = { version = ">=0.28.0,<0.31.0", optional = true }
|
|
50
50
|
boto3 = { version = ">=1.24.74,<2", optional = true }
|
|
51
51
|
psycopg2 = { version = ">=2.8.6,<3", optional = true }
|
|
52
|
-
sqlmodel = { version = ">=0.0.14,<0.0.
|
|
52
|
+
sqlmodel = { version = ">=0.0.14,<0.0.25", optional = true }
|
|
53
53
|
|
|
54
54
|
[tool.poetry.group.dev.dependencies]
|
|
55
|
-
alembic = "1.
|
|
55
|
+
alembic = "1.15.2"
|
|
56
56
|
asgi_lifespan = "2.1.0"
|
|
57
|
-
Faker = "
|
|
57
|
+
Faker = "37.1.0"
|
|
58
58
|
greenlet = "3.1.1"
|
|
59
|
-
httpx = "0.28.
|
|
60
|
-
mypy = { version = "1.
|
|
59
|
+
httpx = "0.28.1"
|
|
60
|
+
mypy = { version = "1.15.0", extras = ["tests"] }
|
|
61
61
|
psycopg2 = { version = "2.9.10", extras = ["binary"] }
|
|
62
|
-
pytest = "8.3.
|
|
63
|
-
pytest-asyncio = "0.
|
|
64
|
-
pytest-cov = "6.
|
|
65
|
-
ruff = "0.
|
|
66
|
-
tox = "4.
|
|
62
|
+
pytest = "8.3.5"
|
|
63
|
+
pytest-asyncio = "0.26.0"
|
|
64
|
+
pytest-cov = "6.1.1"
|
|
65
|
+
ruff = "0.11.5"
|
|
66
|
+
tox = "4.25.0"
|
|
67
67
|
|
|
68
68
|
[tool.poetry.extras]
|
|
69
69
|
asyncpg = ["asyncpg"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|