tiny-service-core 0.1.2__tar.gz → 0.2.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.
Files changed (19) hide show
  1. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/PKG-INFO +5 -6
  2. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/README.md +2 -2
  3. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/pyproject.toml +3 -4
  4. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/config.py +9 -1
  5. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/deps/db.py +5 -5
  6. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/deps/http_client.py +1 -1
  7. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/lifespan.py +19 -6
  8. tiny_service_core-0.2.0/src/core/typing.py +8 -0
  9. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/__init__.py +0 -0
  10. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/app.py +0 -0
  11. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/crypto.py +0 -0
  12. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/deps/__init__.py +0 -0
  13. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/deps/auth.py +0 -0
  14. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/deps/cache.py +0 -0
  15. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/deps/user_ip.py +0 -0
  16. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/excs.py +0 -0
  17. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/lock.py +0 -0
  18. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/main.py +0 -0
  19. {tiny_service_core-0.1.2 → tiny_service_core-0.2.0}/src/core/sentry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: tiny-service-core
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: 🪐 Shared functionality for tiny microservices
5
5
  Keywords: async,fastapi,microservice,core
6
6
  Author: Aliaksei Urbanski
@@ -36,14 +36,13 @@ Requires-Dist: asyncpg ; extra == 'db'
36
36
  Requires-Dist: sentry-sdk[asyncpg,sqlalchemy] ; extra == 'db'
37
37
  Requires-Dist: sqlmodel ; extra == 'db'
38
38
  Requires-Dist: fastapi[standard] ; extra == 'dev'
39
- Requires-Dist: httpx ; extra == 'http-client'
40
- Requires-Dist: sentry-sdk[httpx] ; extra == 'http-client'
39
+ Requires-Dist: httpx2 ; extra == 'http-client'
41
40
  Requires-Dist: python-multipart ; extra == 'multipart'
42
41
  Maintainer: Aliaksei Urbanski
43
42
  Maintainer-email: Aliaksei Urbanski <aliaksei.urbanski@gmail.com>
44
43
  Requires-Python: >=3.12
45
- Project-URL: Issues, https://github.com/Jamim/tiny-service-core/issues
46
44
  Project-URL: Repository, https://github.com/Jamim/tiny-service-core
45
+ Project-URL: Issues, https://github.com/Jamim/tiny-service-core/issues
47
46
  Provides-Extra: cache
48
47
  Provides-Extra: db
49
48
  Provides-Extra: dev
@@ -103,7 +102,7 @@ Current version glues together these components:
103
102
  * [asyncpg][asyncpg]
104
103
  * [Alembic][alembic]
105
104
  - `http-client`
106
- * [HTTPX][httpx]
105
+ * [HTTPX2][httpx2]
107
106
 
108
107
  [fastapi]: https://fastapi.tiangolo.com
109
108
  [pydantic-settings]: https://docs.pydantic.dev/latest/concepts/pydantic_settings/
@@ -112,6 +111,6 @@ Current version glues together these components:
112
111
  [sqlmodel]: https://sqlmodel.tiangolo.com
113
112
  [asyncpg]: https://github.com/MagicStack/asyncpg
114
113
  [alembic]: https://alembic.sqlalchemy.org
115
- [httpx]: https://www.python-httpx.org
114
+ [httpx2]: https://httpx2.pydantic.dev
116
115
 
117
116
  [installing-extras]: https://packaging.python.org/en/latest/tutorials/installing-packages/#installing-extras
@@ -50,7 +50,7 @@ Current version glues together these components:
50
50
  * [asyncpg][asyncpg]
51
51
  * [Alembic][alembic]
52
52
  - `http-client`
53
- * [HTTPX][httpx]
53
+ * [HTTPX2][httpx2]
54
54
 
55
55
  [fastapi]: https://fastapi.tiangolo.com
56
56
  [pydantic-settings]: https://docs.pydantic.dev/latest/concepts/pydantic_settings/
@@ -59,6 +59,6 @@ Current version glues together these components:
59
59
  [sqlmodel]: https://sqlmodel.tiangolo.com
60
60
  [asyncpg]: https://github.com/MagicStack/asyncpg
61
61
  [alembic]: https://alembic.sqlalchemy.org
62
- [httpx]: https://www.python-httpx.org
62
+ [httpx2]: https://httpx2.pydantic.dev
63
63
 
64
64
  [installing-extras]: https://packaging.python.org/en/latest/tutorials/installing-packages/#installing-extras
@@ -3,7 +3,7 @@ name = "tiny-service-core"
3
3
  description = "🪐 Shared functionality for tiny microservices"
4
4
 
5
5
  # https://github.com/astral-sh/uv/issues/11718
6
- version = "0.1.2"
6
+ version = "0.2.0"
7
7
 
8
8
  readme = "README.md"
9
9
  license = { text = "MIT" }
@@ -61,8 +61,7 @@ db = [
61
61
  "sqlmodel",
62
62
  ]
63
63
  http-client = [
64
- "httpx",
65
- "sentry-sdk[httpx]",
64
+ "httpx2",
66
65
  ]
67
66
  multipart = [
68
67
  "python-multipart",
@@ -84,7 +83,7 @@ Repository = "https://github.com/Jamim/tiny-service-core"
84
83
  Issues = "https://github.com/Jamim/tiny-service-core/issues"
85
84
 
86
85
  [build-system]
87
- requires = ["uv_build>=0.9.15,<0.10.0"]
86
+ requires = ["uv_build<1.0"]
88
87
  build-backend = "uv_build"
89
88
 
90
89
  [tool.uv.build-backend]
@@ -41,6 +41,14 @@ class CacheSettings(BaseSettings):
41
41
 
42
42
  class DBSettings(BaseSettings):
43
43
  db_url: str
44
+ db_isolation_level: Literal[
45
+ 'SERIALIZABLE',
46
+ 'REPEATABLE READ',
47
+ 'READ COMMITTED',
48
+ 'READ UNCOMMITTED',
49
+ 'AUTOCOMMIT',
50
+ None,
51
+ ] = None
44
52
 
45
53
 
46
54
  class HTTPClientSettings(BaseSettings):
@@ -50,7 +58,7 @@ class HTTPClientSettings(BaseSettings):
50
58
  OPTIONAL_SETTINGS: dict[str, type[BaseSettings]] = {
51
59
  'redis': CacheSettings,
52
60
  'sqlmodel': DBSettings,
53
- 'httpx': HTTPClientSettings,
61
+ 'httpx2': HTTPClientSettings,
54
62
  }
55
63
 
56
64
  settings_bases = [AppSettings, SentrySettings]
@@ -1,19 +1,19 @@
1
1
  from collections.abc import AsyncGenerator
2
- from typing import Annotated, cast
2
+ from typing import Annotated
3
3
 
4
4
  from fastapi import Depends, Request
5
- from sqlalchemy.orm import sessionmaker
5
+ from sqlalchemy.ext.asyncio import async_sessionmaker
6
6
  from sqlmodel.ext.asyncio.session import AsyncSession
7
7
 
8
8
 
9
9
  async def get_session(request: Request) -> AsyncGenerator[AsyncSession]:
10
- async_session = sessionmaker(
10
+ async_session = async_sessionmaker(
11
11
  request.app.state.db,
12
12
  class_=AsyncSession,
13
13
  expire_on_commit=False,
14
+ autoflush=False,
14
15
  )
15
- session = cast(AsyncSession, async_session())
16
- async with session:
16
+ async with async_session() as session:
17
17
  yield session
18
18
 
19
19
 
@@ -1,7 +1,7 @@
1
1
  from typing import Annotated, cast
2
2
 
3
3
  from fastapi import Depends, Request
4
- from httpx import AsyncClient
4
+ from httpx2 import AsyncClient
5
5
 
6
6
 
7
7
  def get_http_client(request: Request) -> AsyncClient:
@@ -1,14 +1,18 @@
1
1
  import asyncio
2
- from collections.abc import AsyncGenerator, Awaitable, Callable
2
+ from collections.abc import AsyncGenerator
3
3
  from contextlib import asynccontextmanager
4
- from typing import Any, cast
4
+ from typing import cast
5
5
 
6
6
  from fastapi import FastAPI
7
7
  from starlette.datastructures import State
8
8
 
9
9
  from . import settings
10
+ from .typing import CleanUpFunc, CoreInitFunc
10
11
 
11
- type CleanUpFunc = Callable[[], Awaitable[None]]
12
+ try:
13
+ from app.lifespan import INIT_FUNCS as APP_INIT_FUNCS
14
+ except ImportError:
15
+ APP_INIT_FUNCS = []
12
16
 
13
17
 
14
18
  def init_cache(state: State, cache_url: str) -> CleanUpFunc:
@@ -21,12 +25,16 @@ def init_cache(state: State, cache_url: str) -> CleanUpFunc:
21
25
  def init_db(state: State, db_url: str) -> CleanUpFunc:
22
26
  from sqlalchemy.ext.asyncio import create_async_engine
23
27
 
24
- state.db = create_async_engine(db_url)
28
+ kwargs = {}
29
+ if settings.db_isolation_level:
30
+ kwargs['isolation_level'] = settings.db_isolation_level
31
+
32
+ state.db = create_async_engine(db_url, **kwargs)
25
33
  return cast(CleanUpFunc, state.db.dispose)
26
34
 
27
35
 
28
36
  def init_http_client(state: State, retries: int) -> CleanUpFunc:
29
- from httpx import AsyncClient, AsyncHTTPTransport
37
+ from httpx2 import AsyncClient, AsyncHTTPTransport
30
38
 
31
39
  state.http_client = AsyncClient(
32
40
  transport=AsyncHTTPTransport(retries=retries)
@@ -34,7 +42,7 @@ def init_http_client(state: State, retries: int) -> CleanUpFunc:
34
42
  return cast(CleanUpFunc, state.http_client.aclose)
35
43
 
36
44
 
37
- INIT_FUNCS: dict[str, Callable[[State, Any], CleanUpFunc]] = {
45
+ INIT_FUNCS: dict[str, CoreInitFunc] = {
38
46
  'cache_url': init_cache,
39
47
  'db_url': init_db,
40
48
  'http_retries': init_http_client,
@@ -50,6 +58,11 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None]:
50
58
  if value:
51
59
  clean_up_funcs.append(init_func(app.state, value))
52
60
 
61
+ for app_init_func in APP_INIT_FUNCS:
62
+ clean_up = app_init_func(app.state)
63
+ if clean_up:
64
+ clean_up_funcs.append(clean_up)
65
+
53
66
  yield
54
67
 
55
68
  await asyncio.gather(*(func() for func in clean_up_funcs))
@@ -0,0 +1,8 @@
1
+ from collections.abc import Awaitable, Callable
2
+ from typing import Any
3
+
4
+ from starlette.datastructures import State
5
+
6
+ type CleanUpFunc = Callable[[], Awaitable[None]]
7
+ type CoreInitFunc = Callable[[State, Any], CleanUpFunc]
8
+ type AppInitFunc = Callable[[State], CleanUpFunc | None]