fastapi-toolsets 4.1.1__tar.gz → 4.1.2__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.
Files changed (46) hide show
  1. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/PKG-INFO +1 -1
  2. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/pyproject.toml +1 -1
  3. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/__init__.py +1 -1
  4. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/pytest/utils.py +41 -10
  5. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/LICENSE +0 -0
  6. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/README.md +0 -0
  7. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/_imports.py +0 -0
  8. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/cli/__init__.py +0 -0
  9. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/cli/app.py +0 -0
  10. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/cli/commands/__init__.py +0 -0
  11. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/cli/commands/fixtures.py +0 -0
  12. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/cli/config.py +0 -0
  13. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/cli/pyproject.py +0 -0
  14. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/cli/utils.py +0 -0
  15. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/crud/__init__.py +0 -0
  16. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/crud/factory.py +0 -0
  17. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/crud/search.py +0 -0
  18. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/db.py +0 -0
  19. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/dependencies.py +0 -0
  20. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/exceptions/__init__.py +0 -0
  21. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/exceptions/exceptions.py +0 -0
  22. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/exceptions/handler.py +0 -0
  23. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/fixtures/__init__.py +0 -0
  24. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/fixtures/enum.py +0 -0
  25. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/fixtures/registry.py +0 -0
  26. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/fixtures/utils.py +0 -0
  27. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/logger.py +0 -0
  28. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/metrics/__init__.py +0 -0
  29. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/metrics/handler.py +0 -0
  30. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/metrics/registry.py +0 -0
  31. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/models/__init__.py +0 -0
  32. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/models/columns.py +0 -0
  33. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/models/watched.py +0 -0
  34. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/py.typed +0 -0
  35. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/pytest/__init__.py +0 -0
  36. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/pytest/plugin.py +0 -0
  37. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/schemas.py +0 -0
  38. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/security/__init__.py +0 -0
  39. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/security/abc.py +0 -0
  40. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/security/oauth.py +0 -0
  41. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/security/sources/__init__.py +0 -0
  42. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/security/sources/bearer.py +0 -0
  43. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/security/sources/cookie.py +0 -0
  44. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/security/sources/header.py +0 -0
  45. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/security/sources/multi.py +0 -0
  46. {fastapi_toolsets-4.1.1 → fastapi_toolsets-4.1.2}/src/fastapi_toolsets/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-toolsets
3
- Version: 4.1.1
3
+ Version: 4.1.2
4
4
  Summary: Production-ready utilities for FastAPI applications
5
5
  Keywords: fastapi,sqlalchemy,postgresql
6
6
  Author: d3vyce
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fastapi-toolsets"
3
- version = "4.1.1"
3
+ version = "4.1.2"
4
4
  description = "Production-ready utilities for FastAPI applications"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -21,4 +21,4 @@ Example usage:
21
21
  return Response(data={"user": user.username}, message="Success")
22
22
  """
23
23
 
24
- __version__ = "4.1.1"
24
+ __version__ = "4.1.2"
@@ -7,7 +7,7 @@ from typing import Any
7
7
 
8
8
  from httpx import ASGITransport, AsyncClient
9
9
  from sqlalchemy import text
10
- from sqlalchemy.engine import make_url
10
+ from sqlalchemy.engine import URL, make_url
11
11
  from sqlalchemy.ext.asyncio import (
12
12
  AsyncSession,
13
13
  async_sessionmaker,
@@ -63,6 +63,8 @@ def worker_database_url(database_url: str, default_test_db: str) -> str:
63
63
  async def create_worker_database(
64
64
  database_url: str,
65
65
  default_test_db: str = "test_db",
66
+ *,
67
+ server_url: str | None = None,
66
68
  ) -> AsyncGenerator[str, None]:
67
69
  """Create and drop a per-worker database for pytest-xdist isolation.
68
70
 
@@ -74,10 +76,13 @@ async def create_worker_database(
74
76
  name (e.g. ``_gw0``). Otherwise it is suffixed with *default_test_db*.
75
77
 
76
78
  Args:
77
- database_url: Original database connection URL (used as the server
78
- connection and as the base for the worker database name).
79
+ database_url: Original database connection URL (used as the base for
80
+ the worker database name).
79
81
  default_test_db: Suffix appended to the database name when
80
82
  ``PYTEST_XDIST_WORKER`` is not set. Defaults to ``"test_db"``.
83
+ server_url: URL used for server-level DDL (must point to an existing
84
+ database on the same server). Defaults to *database_url* with the
85
+ database omitted, letting asyncpg fall back to the username.
81
86
 
82
87
  Yields:
83
88
  The worker-specific database URL.
@@ -86,7 +91,7 @@ async def create_worker_database(
86
91
  ```python
87
92
  from fastapi_toolsets.pytest import create_worker_database, create_db_session
88
93
 
89
- DATABASE_URL = "postgresql+asyncpg://postgres:postgres@localhost/test_db"
94
+ DATABASE_URL = "postgresql+asyncpg://postgres:postgres@localhost/myapp"
90
95
 
91
96
  @pytest.fixture(scope="session")
92
97
  async def worker_db_url():
@@ -107,11 +112,21 @@ async def create_worker_database(
107
112
  worker_db_name = make_url(worker_url).database
108
113
  assert worker_db_name is not None
109
114
 
110
- engine = create_async_engine(database_url, isolation_level="AUTOCOMMIT")
115
+ _parsed = make_url(database_url)
116
+ _server_url = server_url or URL.create(
117
+ drivername=_parsed.drivername,
118
+ username=_parsed.username,
119
+ password=_parsed.password,
120
+ host=_parsed.host,
121
+ port=_parsed.port,
122
+ query=_parsed.query,
123
+ ).render_as_string(hide_password=False)
124
+
125
+ engine = create_async_engine(_server_url, isolation_level="AUTOCOMMIT")
111
126
  try:
112
127
  async with engine.connect() as conn:
113
128
  await conn.execute(text(f"DROP DATABASE IF EXISTS {worker_db_name}"))
114
- await create_database(db_name=worker_db_name, server_url=database_url)
129
+ await create_database(db_name=worker_db_name, server_url=_server_url)
115
130
 
116
131
  yield worker_url
117
132
 
@@ -126,6 +141,7 @@ async def create_async_client(
126
141
  app: Any,
127
142
  base_url: str = "http://test",
128
143
  dependency_overrides: dict[Callable[..., Any], Callable[..., Any]] | None = None,
144
+ **kwargs: Any,
129
145
  ) -> AsyncGenerator[AsyncClient, None]:
130
146
  """Create an async httpx client for testing FastAPI applications.
131
147
 
@@ -135,6 +151,9 @@ async def create_async_client(
135
151
  dependency_overrides: Optional mapping of original dependencies to
136
152
  their test replacements. Applied via ``app.dependency_overrides``
137
153
  before yielding and cleaned up after.
154
+ **kwargs: Additional keyword arguments forwarded to
155
+ :class:`httpx.AsyncClient` (e.g. ``headers``, ``cookies``,
156
+ ``auth``, ``timeout``).
138
157
 
139
158
  Yields:
140
159
  An AsyncClient configured for the app.
@@ -182,7 +201,9 @@ async def create_async_client(
182
201
 
183
202
  transport = ASGITransport(app=app)
184
203
  try:
185
- async with AsyncClient(transport=transport, base_url=base_url) as client:
204
+ async with AsyncClient(
205
+ transport=transport, base_url=base_url, **kwargs
206
+ ) as client:
186
207
  yield client
187
208
  finally:
188
209
  if dependency_overrides:
@@ -199,6 +220,8 @@ async def create_db_session(
199
220
  expire_on_commit: bool = False,
200
221
  drop_tables: bool = True,
201
222
  cleanup: bool = False,
223
+ engine_kwargs: dict[str, Any] | None = None,
224
+ session_kwargs: dict[str, Any] | None = None,
202
225
  ) -> AsyncGenerator[AsyncSession, None]:
203
226
  """Create a database session for testing.
204
227
 
@@ -213,6 +236,12 @@ async def create_db_session(
213
236
  drop_tables: Drop tables after test. Defaults to True.
214
237
  cleanup: Truncate all tables after test using
215
238
  :func:`cleanup_tables`. Defaults to False.
239
+ engine_kwargs: Additional keyword arguments forwarded to
240
+ :func:`sqlalchemy.ext.asyncio.create_async_engine`
241
+ (e.g. ``pool_size``, ``connect_args``).
242
+ session_kwargs: Additional keyword arguments forwarded to
243
+ :class:`sqlalchemy.ext.asyncio.async_sessionmaker`
244
+ (e.g. ``autoflush``, ``class_``).
216
245
 
217
246
  Yields:
218
247
  An AsyncSession ready for database operations.
@@ -237,15 +266,17 @@ async def create_db_session(
237
266
  await db_session.commit()
238
267
  ```
239
268
  """
240
- engine = create_async_engine(database_url, echo=echo)
269
+ engine = create_async_engine(database_url, echo=echo, **(engine_kwargs or {}))
241
270
 
242
271
  try:
243
- # Create tables
244
272
  async with engine.begin() as conn:
245
273
  await conn.run_sync(base.metadata.create_all)
246
274
 
247
275
  session_maker = async_sessionmaker(
248
- engine, expire_on_commit=expire_on_commit, class_=EventSession
276
+ engine,
277
+ expire_on_commit=expire_on_commit,
278
+ class_=EventSession,
279
+ **(session_kwargs or {}),
249
280
  )
250
281
  async with session_maker() as session:
251
282
  yield session