nlbone 0.4.0__py3-none-any.whl → 0.4.1__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.
Files changed (46) hide show
  1. nlbone/adapters/auth/__init__.py +1 -1
  2. nlbone/adapters/auth/keycloak.py +3 -2
  3. nlbone/adapters/db/__init__.py +2 -2
  4. nlbone/adapters/db/sqlalchemy/__init__.py +4 -4
  5. nlbone/adapters/db/sqlalchemy/base.py +0 -2
  6. nlbone/adapters/db/sqlalchemy/engine.py +4 -3
  7. nlbone/adapters/db/sqlalchemy/query_builder.py +27 -11
  8. nlbone/adapters/db/sqlalchemy/repository.py +4 -2
  9. nlbone/adapters/db/sqlalchemy/schema.py +5 -5
  10. nlbone/adapters/db/sqlalchemy/uow.py +3 -2
  11. nlbone/adapters/http_clients/uploadchi.py +27 -11
  12. nlbone/adapters/http_clients/uploadchi_async.py +29 -7
  13. nlbone/adapters/messaging/event_bus.py +3 -0
  14. nlbone/config/logging.py +3 -8
  15. nlbone/config/settings.py +11 -22
  16. nlbone/container.py +6 -5
  17. nlbone/core/application/events.py +5 -1
  18. nlbone/core/application/use_case.py +3 -1
  19. nlbone/core/domain/base.py +4 -0
  20. nlbone/core/ports/__init__.py +3 -3
  21. nlbone/core/ports/auth.py +1 -0
  22. nlbone/core/ports/event_bus.py +3 -0
  23. nlbone/core/ports/files.py +26 -5
  24. nlbone/core/ports/repo.py +5 -2
  25. nlbone/core/ports/uow.py +3 -0
  26. nlbone/interfaces/api/dependencies/__init__.py +11 -3
  27. nlbone/interfaces/api/dependencies/async_auth.py +61 -0
  28. nlbone/interfaces/api/dependencies/auth.py +5 -3
  29. nlbone/interfaces/api/dependencies/db.py +4 -2
  30. nlbone/interfaces/api/dependencies/uow.py +2 -1
  31. nlbone/interfaces/api/exception_handlers.py +17 -15
  32. nlbone/interfaces/api/exceptions.py +1 -2
  33. nlbone/interfaces/api/middleware/__init__.py +2 -2
  34. nlbone/interfaces/api/middleware/access_log.py +12 -8
  35. nlbone/interfaces/api/middleware/add_request_context.py +55 -52
  36. nlbone/interfaces/api/middleware/authentication.py +4 -1
  37. nlbone/interfaces/api/pagination/__init__.py +4 -5
  38. nlbone/interfaces/api/pagination/offset_base.py +0 -2
  39. nlbone/interfaces/cli/init_db.py +3 -0
  40. nlbone/utils/context.py +14 -4
  41. nlbone/utils/time.py +1 -1
  42. {nlbone-0.4.0.dist-info → nlbone-0.4.1.dist-info}/METADATA +1 -9
  43. nlbone-0.4.1.dist-info/RECORD +72 -0
  44. nlbone-0.4.0.dist-info/RECORD +0 -71
  45. {nlbone-0.4.0.dist-info → nlbone-0.4.1.dist-info}/WHEEL +0 -0
  46. {nlbone-0.4.0.dist-info → nlbone-0.4.1.dist-info}/licenses/LICENSE +0 -0
nlbone/core/ports/repo.py CHANGED
@@ -1,16 +1,19 @@
1
1
  from __future__ import annotations
2
- from typing import Iterable, Optional, Protocol, TypeVar, List
2
+
3
+ from typing import Iterable, List, Optional, Protocol, TypeVar
3
4
 
4
5
  T = TypeVar("T")
5
6
 
7
+
6
8
  class Repository(Protocol[T]): # ← نه Protocol, Generic[T]
7
9
  def get(self, id) -> Optional[T]: ...
8
10
  def add(self, obj: T) -> None: ...
9
11
  def remove(self, obj: T) -> None: ...
10
12
  def list(self, *, limit: int | None = None, offset: int = 0) -> Iterable[T]: ...
11
13
 
14
+
12
15
  class AsyncRepository(Protocol[T]):
13
16
  async def get(self, id) -> Optional[T]: ...
14
17
  def add(self, obj: T) -> None: ...
15
18
  async def remove(self, obj: T) -> None: ...
16
- async def list(self, *, limit: int | None = None, offset: int = 0) -> List[T]: ...
19
+ async def list(self, *, limit: int | None = None, offset: int = 0) -> List[T]: ...
nlbone/core/ports/uow.py CHANGED
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
+
2
3
  from typing import Protocol, runtime_checkable
3
4
 
5
+
4
6
  @runtime_checkable
5
7
  class UnitOfWork(Protocol):
6
8
  def __enter__(self) -> "UnitOfWork": ...
@@ -8,6 +10,7 @@ class UnitOfWork(Protocol):
8
10
  def commit(self) -> None: ...
9
11
  def rollback(self) -> None: ...
10
12
 
13
+
11
14
  @runtime_checkable
12
15
  class AsyncUnitOfWork(Protocol):
13
16
  async def __aenter__(self) -> "AsyncUnitOfWork": ...
@@ -1,3 +1,11 @@
1
- from .db import get_session, get_async_session
2
- from .auth import has_access, client_has_access, current_client_id, current_user_id, current_request, user_authenticated
3
- from .uow import get_uow, get_async_uow
1
+ from .async_auth import client_has_access, current_request, current_user_id, has_access, user_authenticated
2
+ from .auth import ( # noqa: F811
3
+ client_has_access,
4
+ current_client_id,
5
+ current_request,
6
+ current_user_id,
7
+ has_access,
8
+ user_authenticated,
9
+ )
10
+ from .db import get_async_session, get_session
11
+ from .uow import get_async_uow, get_uow
@@ -0,0 +1,61 @@
1
+ import functools
2
+
3
+ from nlbone.adapters.auth import KeycloakAuthService
4
+ from nlbone.interfaces.api.exceptions import ForbiddenException, UnauthorizedException
5
+ from nlbone.utils.context import current_request
6
+
7
+
8
+ async def current_user_id() -> int:
9
+ user_id = current_request().state.user_id
10
+ if user_id is not None:
11
+ return int(user_id)
12
+ raise UnauthorizedException()
13
+
14
+
15
+ async def current_client_id() -> str:
16
+ request = current_request()
17
+ if client_id := KeycloakAuthService().get_client_id(request.state.token):
18
+ return str(client_id)
19
+ raise UnauthorizedException()
20
+
21
+
22
+ def client_has_access(*, permissions=None):
23
+ def decorator(func):
24
+ @functools.wraps(func)
25
+ async def wrapper(*args, **kwargs):
26
+ request = current_request()
27
+ if not KeycloakAuthService().client_has_access(request.state.token, permissions=permissions):
28
+ raise ForbiddenException(f"Forbidden {permissions}")
29
+
30
+ return await func(*args, **kwargs)
31
+
32
+ return wrapper
33
+
34
+ return decorator
35
+
36
+
37
+ def user_authenticated(func):
38
+ @functools.wraps(func)
39
+ async def wrapper(*args, **kwargs):
40
+ if not await current_user_id():
41
+ raise UnauthorizedException()
42
+ return await func(*args, **kwargs)
43
+
44
+ return wrapper
45
+
46
+
47
+ def has_access(*, permissions=None):
48
+ def decorator(func):
49
+ @functools.wraps(func)
50
+ async def wrapper(*args, **kwargs):
51
+ request = current_request()
52
+ if not await current_user_id():
53
+ raise UnauthorizedException()
54
+ if not KeycloakAuthService().has_access(request.state.token, permissions=permissions):
55
+ raise ForbiddenException(f"Forbidden {permissions}")
56
+
57
+ return await func(*args, **kwargs)
58
+
59
+ return wrapper
60
+
61
+ return decorator
@@ -30,15 +30,16 @@ def client_has_access(*, permissions=None):
30
30
  return func(*args, **kwargs)
31
31
 
32
32
  return wrapper
33
+
33
34
  return decorator
34
35
 
35
36
 
36
37
  def user_authenticated(func):
37
38
  @functools.wraps(func)
38
- async def wrapper(*args, **kwargs):
39
+ def wrapper(*args, **kwargs):
39
40
  if not current_user_id():
40
41
  raise UnauthorizedException()
41
- return await func(*args, **kwargs)
42
+ return func(*args, **kwargs)
42
43
 
43
44
  return wrapper
44
45
 
@@ -56,4 +57,5 @@ def has_access(*, permissions=None):
56
57
  return func(*args, **kwargs)
57
58
 
58
59
  return wrapper
59
- return decorator
60
+
61
+ return decorator
@@ -1,8 +1,9 @@
1
1
  from __future__ import annotations
2
+
2
3
  from typing import AsyncGenerator, Generator
3
4
 
4
- from sqlalchemy.orm import Session
5
5
  from sqlalchemy.ext.asyncio import AsyncSession
6
+ from sqlalchemy.orm import Session
6
7
 
7
8
  from nlbone.adapters.db.sqlalchemy.engine import async_session, sync_session
8
9
 
@@ -11,6 +12,7 @@ async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
11
12
  async with async_session() as s:
12
13
  yield s
13
14
 
15
+
14
16
  def get_session() -> Generator[Session, None, None]:
15
17
  with sync_session() as s:
16
- yield s
18
+ yield s
@@ -1,11 +1,12 @@
1
1
  from __future__ import annotations
2
+
2
3
  from collections.abc import Iterator
3
4
  from typing import AsyncIterator
4
5
 
5
6
  from fastapi import Request
6
7
 
7
8
  from nlbone.adapters.db.sqlalchemy import AsyncSqlAlchemyUnitOfWork
8
- from nlbone.core.ports.uow import UnitOfWork, AsyncUnitOfWork
9
+ from nlbone.core.ports.uow import AsyncUnitOfWork, UnitOfWork
9
10
 
10
11
 
11
12
  def get_uow(request: Request) -> Iterator[UnitOfWork]:
@@ -1,32 +1,33 @@
1
1
  from __future__ import annotations
2
- from typing import Any, Optional, Mapping
2
+
3
+ from typing import Any, Mapping, Optional
3
4
  from uuid import uuid4
4
5
 
5
6
  from fastapi import FastAPI, Request
6
- from fastapi.responses import JSONResponse
7
+ from fastapi import HTTPException as FastAPIHTTPException
7
8
  from fastapi.exceptions import RequestValidationError
9
+ from fastapi.responses import JSONResponse
8
10
  from pydantic import ValidationError
9
- from fastapi import HTTPException as FastAPIHTTPException
10
11
  from starlette.exceptions import HTTPException as StarletteHTTPException
11
12
 
12
13
  from .exceptions import BaseHttpException
13
14
 
14
-
15
15
  # ---- Helpers ---------------------------------------------------------------
16
16
 
17
+
17
18
  def _ensure_trace_id(request: Request) -> str:
18
19
  rid = request.headers.get("X-Request-Id") or request.headers.get("X-Trace-Id")
19
20
  return rid or str(uuid4())
20
21
 
21
22
 
22
23
  def _json_response(
23
- request: Request,
24
- status_code: int,
25
- *,
26
- detail: Any,
27
- headers: Optional[Mapping[str, str]] = None,
28
- trace_id: Optional[str] = None,
29
- extra: Optional[Mapping[str, Any]] = None,
24
+ request: Request,
25
+ status_code: int,
26
+ *,
27
+ detail: Any,
28
+ headers: Optional[Mapping[str, str]] = None,
29
+ trace_id: Optional[str] = None,
30
+ extra: Optional[Mapping[str, Any]] = None,
30
31
  ) -> JSONResponse:
31
32
  payload: dict[str, Any] = {"detail": detail}
32
33
  if extra:
@@ -44,11 +45,12 @@ def _json_response(
44
45
 
45
46
  # ---- Public Installer ------------------------------------------------------
46
47
 
48
+
47
49
  def install_exception_handlers(
48
- app: FastAPI,
49
- *,
50
- logger: Any = None,
51
- expose_server_errors: bool = False,
50
+ app: FastAPI,
51
+ *,
52
+ logger: Any = None,
53
+ expose_server_errors: bool = False,
52
54
  ) -> None:
53
55
  @app.exception_handler(BaseHttpException)
54
56
  async def _handle_base_http_exception(request: Request, exc: BaseHttpException):
@@ -1,4 +1,5 @@
1
1
  from typing import Any, Iterable
2
+
2
3
  from fastapi import HTTPException, status
3
4
 
4
5
 
@@ -77,5 +78,3 @@ class UnprocessableEntityException(BaseHttpException):
77
78
  class LogicalValidationException(UnprocessableEntityException):
78
79
  def __init__(self, detail: str, loc: Iterable[Any] | None = None, type_: str = "logical_error"):
79
80
  super().__init__(detail=detail, loc=loc, type_=type_)
80
-
81
-
@@ -1,3 +1,3 @@
1
- from .authentication import AuthenticationMiddleware
1
+ from .access_log import AccessLogMiddleware
2
2
  from .add_request_context import AddRequestContextMiddleware
3
- from .access_log import AccessLogMiddleware
3
+ from .authentication import AuthenticationMiddleware
@@ -1,5 +1,6 @@
1
1
  import time
2
2
  from typing import Callable
3
+
3
4
  from fastapi import Request
4
5
  from starlette.middleware.base import BaseHTTPMiddleware
5
6
 
@@ -7,6 +8,7 @@ from nlbone.config.logging import get_logger
7
8
 
8
9
  logger = get_logger(__name__)
9
10
 
11
+
10
12
  class AccessLogMiddleware(BaseHTTPMiddleware):
11
13
  async def dispatch(self, request: Request, call_next: Callable):
12
14
  start = time.perf_counter()
@@ -20,11 +22,13 @@ class AccessLogMiddleware(BaseHTTPMiddleware):
20
22
  raise
21
23
  finally:
22
24
  dur_ms = int((time.perf_counter() - start) * 1000)
23
- logger.info({
24
- "event": "access",
25
- "method": request.method,
26
- "path": request.url.path,
27
- "status": status_code,
28
- "duration_ms": dur_ms,
29
- "query": request.url.query,
30
- })
25
+ logger.info(
26
+ {
27
+ "event": "access",
28
+ "method": request.method,
29
+ "path": request.url.path,
30
+ "status": status_code,
31
+ "duration_ms": dur_ms,
32
+ "query": request.url.query,
33
+ }
34
+ )
@@ -1,52 +1,55 @@
1
- from __future__ import annotations
2
- from typing import Optional
3
- from uuid import uuid4
4
-
5
- from starlette.datastructures import Headers
6
- from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
7
- from starlette.requests import Request
8
-
9
- from nlbone import config
10
- from nlbone.utils.context import request_ctx, request_id_ctx, bind_context, reset_context
11
-
12
-
13
- def mock_request(user=None, token: Optional[str] = None):
14
- request = Request({
15
- "type": "http",
16
- "headers": Headers({"User-Agent": "Testing-Agent"}).raw,
17
- "client": {"host": "192.168.1.1", "port": 80},
18
- "method": "GET",
19
- "path": "/__test__",
20
- })
21
- request.state.user = user
22
- request.state.token = token
23
- return request
24
-
25
-
26
- def current_request() -> Optional[Request]:
27
- req = request_ctx.get()
28
- if config.ENV == 'test' and req is None:
29
- return mock_request()
30
- return req
31
-
32
-
33
- def current_request_id() -> Optional[str]:
34
- return request_id_ctx.get()
35
-
36
-
37
- class AddRequestContextMiddleware(BaseHTTPMiddleware):
38
- async def dispatch(self, request: Request, call_next: RequestResponseEndpoint):
39
- incoming_req_id = request.headers.get("X-Request-ID")
40
- req_id = incoming_req_id or str(uuid4())
41
-
42
- user_id = getattr(getattr(request, "state", None), "user_id", None) or request.headers.get("X-User-Id")
43
- ip = request.client.host if request.client else None
44
- ua = request.headers.get("user-agent")
45
-
46
- tokens = bind_context(request=request, request_id=req_id, user_id=user_id, ip=ip, user_agent=ua)
47
- try:
48
- response = await call_next(request)
49
- response.headers.setdefault("X-Request-ID", req_id)
50
- return response
51
- finally:
52
- reset_context(tokens)
1
+ from __future__ import annotations
2
+
3
+ from typing import Optional
4
+ from uuid import uuid4
5
+
6
+ from starlette.datastructures import Headers
7
+ from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
8
+ from starlette.requests import Request
9
+
10
+ from nlbone.config.settings import get_settings
11
+ from nlbone.utils.context import bind_context, request_ctx, request_id_ctx, reset_context
12
+
13
+
14
+ def mock_request(user=None, token: Optional[str] = None):
15
+ request = Request(
16
+ {
17
+ "type": "http",
18
+ "headers": Headers({"User-Agent": "Testing-Agent"}).raw,
19
+ "client": {"host": "192.168.1.1", "port": 80},
20
+ "method": "GET",
21
+ "path": "/__test__",
22
+ }
23
+ )
24
+ request.state.user = user
25
+ request.state.token = token
26
+ return request
27
+
28
+
29
+ def current_request() -> Optional[Request]:
30
+ req = request_ctx.get()
31
+ if get_settings().ENV == "local" and req is None:
32
+ return mock_request()
33
+ return req
34
+
35
+
36
+ def current_request_id() -> Optional[str]:
37
+ return request_id_ctx.get()
38
+
39
+
40
+ class AddRequestContextMiddleware(BaseHTTPMiddleware):
41
+ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint):
42
+ incoming_req_id = request.headers.get("X-Request-ID")
43
+ req_id = incoming_req_id or str(uuid4())
44
+
45
+ user_id = getattr(getattr(request, "state", None), "user_id", None) or request.headers.get("X-User-Id")
46
+ ip = request.client.host if request.client else None
47
+ ua = request.headers.get("user-agent")
48
+
49
+ tokens = bind_context(request=request, request_id=req_id, user_id=user_id, ip=ip, user_agent=ua)
50
+ try:
51
+ response = await call_next(request)
52
+ response.headers.setdefault("X-Request-ID", req_id)
53
+ return response
54
+ finally:
55
+ reset_context(tokens)
@@ -1,9 +1,11 @@
1
- from typing import Optional, Callable, Union
1
+ from typing import Callable, Optional, Union
2
+
2
3
  from fastapi import Request
3
4
  from starlette.middleware.base import BaseHTTPMiddleware
4
5
 
5
6
  try:
6
7
  from dependency_injector import providers
8
+
7
9
  ProviderType = providers.Provider # type: ignore
8
10
  except Exception:
9
11
  ProviderType = object
@@ -14,6 +16,7 @@ from nlbone.core.ports.auth import AuthService
14
16
  def _to_factory(auth: Union[AuthService, Callable[[], AuthService], ProviderType]):
15
17
  try:
16
18
  from dependency_injector import providers as _p # type: ignore
19
+
17
20
  if isinstance(auth, _p.Provider):
18
21
  return auth
19
22
  except Exception:
@@ -1,13 +1,12 @@
1
1
  from typing import Generic, List, Optional, TypeVar
2
- from pydantic import BaseModel
2
+
3
3
  from fastapi import Depends
4
+ from pydantic import BaseModel
4
5
 
5
- from .offset_base import PaginateResponse, PaginateRequest
6
+ from .offset_base import PaginateRequest, PaginateResponse
6
7
 
7
8
 
8
- def get_pagination(
9
- req: PaginateRequest = Depends(PaginateRequest)
10
- ) -> PaginateRequest:
9
+ def get_pagination(req: PaginateRequest = Depends(PaginateRequest)) -> PaginateRequest:
11
10
  return req
12
11
 
13
12
 
@@ -3,7 +3,6 @@ from math import ceil
3
3
  from typing import Any, Optional
4
4
 
5
5
  from fastapi import Query
6
- from sqlalchemy import asc, desc
7
6
 
8
7
 
9
8
  class PaginateRequest:
@@ -76,7 +75,6 @@ class PaginateRequest:
76
75
  return filters_dict
77
76
 
78
77
 
79
-
80
78
  class PaginateResponse:
81
79
  """
82
80
  Lightweight response shaper. If total_count is None → returns just items.
@@ -1,8 +1,10 @@
1
1
  import argparse
2
+
2
3
  import anyio
3
4
 
4
5
  from nlbone.adapters.db.sqlalchemy.schema import init_db_async, init_db_sync
5
6
 
7
+
6
8
  def main() -> None:
7
9
  parser = argparse.ArgumentParser(description="Initialize database schema (create_all).")
8
10
  parser.add_argument("--async", dest="use_async", action="store_true", help="Use AsyncEngine")
@@ -13,5 +15,6 @@ def main() -> None:
13
15
  else:
14
16
  init_db_sync()
15
17
 
18
+
16
19
  if __name__ == "__main__":
17
20
  main()
nlbone/utils/context.py CHANGED
@@ -7,9 +7,15 @@ user_id_ctx: ContextVar[str | None] = ContextVar("user_id", default=None)
7
7
  ip_ctx: ContextVar[str | None] = ContextVar("ip", default=None)
8
8
  user_agent_ctx: ContextVar[str | None] = ContextVar("user_agent", default=None)
9
9
 
10
- def bind_context(*, request: Any | None = None, request_id: str | None = None,
11
- user_id: str | None = None, ip: str | None = None,
12
- user_agent: str | None = None) -> dict[ContextVar, Any]:
10
+
11
+ def bind_context(
12
+ *,
13
+ request: Any | None = None,
14
+ request_id: str | None = None,
15
+ user_id: str | None = None,
16
+ ip: str | None = None,
17
+ user_agent: str | None = None,
18
+ ) -> dict[ContextVar, Any]:
13
19
  tokens: dict[ContextVar, Any] = {}
14
20
  if request is not None:
15
21
  tokens[request_ctx] = request_ctx.set(request)
@@ -23,20 +29,24 @@ def bind_context(*, request: Any | None = None, request_id: str | None = None,
23
29
  tokens[user_agent_ctx] = user_agent_ctx.set(user_agent)
24
30
  return tokens
25
31
 
32
+
26
33
  def reset_context(tokens: dict[ContextVar, Any]):
27
34
  for var, token in tokens.items():
28
35
  var.reset(token)
29
36
 
37
+
30
38
  def current_request():
31
39
  return request_ctx.get()
32
40
 
41
+
33
42
  def current_request_id() -> Optional[str]:
34
43
  return request_id_ctx.get()
35
44
 
45
+
36
46
  def current_context_dict() -> dict[str, Any]:
37
47
  return {
38
48
  "request_id": request_id_ctx.get(),
39
49
  "user_id": user_id_ctx.get(),
40
50
  "ip": ip_ctx.get(),
41
51
  "user_agent": user_agent_ctx.get(),
42
- }
52
+ }
nlbone/utils/time.py CHANGED
@@ -2,4 +2,4 @@ from datetime import datetime, timezone
2
2
 
3
3
 
4
4
  def now() -> datetime:
5
- return datetime.now(timezone.utc)
5
+ return datetime.now(timezone.utc)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nlbone
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Backbone package for interfaces and infrastructure in Python projects
5
5
  Author-email: Amir Hosein Kahkbazzadeh <a.khakbazzadeh@gmail.com>
6
6
  License: MIT
@@ -17,14 +17,6 @@ Requires-Dist: python-keycloak==5.8.1
17
17
  Requires-Dist: sqlalchemy>=2.0
18
18
  Requires-Dist: starlette>=0.47
19
19
  Requires-Dist: uvicorn>=0.35
20
- Provides-Extra: dev
21
- Requires-Dist: mypy>=1.10; extra == 'dev'
22
- Requires-Dist: pre-commit>=3.7; extra == 'dev'
23
- Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
24
- Requires-Dist: pytest>=8.0; extra == 'dev'
25
- Requires-Dist: ruff>=0.5; extra == 'dev'
26
- Requires-Dist: tomli; extra == 'dev'
27
- Requires-Dist: twine; extra == 'dev'
28
20
  Description-Content-Type: text/markdown
29
21
 
30
22
  # nlbone
@@ -0,0 +1,72 @@
1
+ nlbone/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ nlbone/container.py,sha256=TrjMmUNXfwW4R4dRftK1GOpYu3wqfhixtnwuZkxVWvI,2104
3
+ nlbone/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ nlbone/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ nlbone/adapters/auth/__init__.py,sha256=hkDHvsFhw_UiOHG9ZSMqjiAhK4wumEforitveSZswVw,42
6
+ nlbone/adapters/auth/keycloak.py,sha256=adZ9r-IPybSzWEQCRlPcxeDjPf8rKVf1xq3zgpMTqrY,2616
7
+ nlbone/adapters/db/__init__.py,sha256=A8O5Vk2o71HumV7pQBXOszWSzOfLVn5FqbHOAUCWugk,218
8
+ nlbone/adapters/db/memory.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ nlbone/adapters/db/postgres.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ nlbone/adapters/db/sqlalchemy/__init__.py,sha256=6JYJH0xZs3aR-zuyMpRhsdzFugmqz8nprwTQLprqhZc,313
11
+ nlbone/adapters/db/sqlalchemy/base.py,sha256=kha9xmklzhuQAK8QEkNBn-mAHq8dUKbOM-3abaBpWmQ,71
12
+ nlbone/adapters/db/sqlalchemy/engine.py,sha256=UCegauVB1gvo42ThytYnn5VIcQBwR-5xhcXYFApRFNk,3448
13
+ nlbone/adapters/db/sqlalchemy/query_builder.py,sha256=U5pqpCfJKuMIxIEHyodoHuPgE8jf53slC1ScKZR5xa4,8653
14
+ nlbone/adapters/db/sqlalchemy/repository.py,sha256=J_DBE73JhHPYCk90c5-O7lQtZbxDgqjjN9OcWy4Omvs,1660
15
+ nlbone/adapters/db/sqlalchemy/schema.py,sha256=7ELexoAnbSjEJ3JYDNRSKOuraS51DupZ6H8QIkuGcsM,1043
16
+ nlbone/adapters/db/sqlalchemy/uow.py,sha256=nRxNpY-WoWHpym-XeZ8VHm0MYvtB9wuopOeNdV_ebk8,2088
17
+ nlbone/adapters/http_clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ nlbone/adapters/http_clients/email_gateway.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ nlbone/adapters/http_clients/uploadchi.py,sha256=BGdGC-p8EmXYn29da577Kas2CzZVDAb9XJ9xx2LJioY,4713
20
+ nlbone/adapters/http_clients/uploadchi_async.py,sha256=hBx0jzYYZAX1DCkImZ98zdUob8D9PQH7jykDXIjwG9I,3866
21
+ nlbone/adapters/messaging/__init__.py,sha256=UDAwu3s-JQmOZjWz2Nu0SgHhnkbeOhKDH_zLD75oWMY,40
22
+ nlbone/adapters/messaging/event_bus.py,sha256=w-NPwDiPMLFPU_enRQCtfQXOALsXfg31u57R8sG_-1U,781
23
+ nlbone/adapters/messaging/redis.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ nlbone/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ nlbone/config/logging.py,sha256=T7Wm61Bu6QqhmnGKdWRQBqnVYKOwaFguiNs2CbJwYfE,5010
26
+ nlbone/config/settings.py,sha256=7DoouDUrWN_fZmo1NngoFFNRMY6kNVq4VGpocnYVeQ4,3208
27
+ nlbone/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ nlbone/core/application/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ nlbone/core/application/events.py,sha256=eQGLE0aZHuWJsy9J-qRse4CMXOtweH9-2rQ7AIPRMEQ,614
30
+ nlbone/core/application/services.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ nlbone/core/application/use_case.py,sha256=3GMQZ3CFK5cbLoBNBgohPft6GBq2j9_wr8iKRq_osQA,247
32
+ nlbone/core/application/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ nlbone/core/domain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ nlbone/core/domain/base.py,sha256=5oUfbpaI8juJ28Api8J9IXOSm55VI2bp4QNhA0U8h2Y,1251
35
+ nlbone/core/domain/events.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ nlbone/core/domain/models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
+ nlbone/core/ports/__init__.py,sha256=gx-Ubj7h-1vvnu56sNnRqmer7HHfW3rX2WLl-0AX5U0,214
38
+ nlbone/core/ports/auth.py,sha256=Gh0yQsxx2OD6pDH2_p-khsA-bVoypP1juuqMoSfjZUo,493
39
+ nlbone/core/ports/event_bus.py,sha256=_Om1GOOT-F325oV6_LJXtLdx4vu5i7KrpTDD3qPJXU0,325
40
+ nlbone/core/ports/files.py,sha256=1k-Vm0ld89EnFK2wybSXIJm5gQNpeuO92PD7d4VMh8s,1737
41
+ nlbone/core/ports/messaging.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
+ nlbone/core/ports/repo.py,sha256=zOw8CTMAu5DKKy2wZpT3_6JWWjaJCDt7q4dOiJYrCOQ,651
43
+ nlbone/core/ports/uow.py,sha256=SmBdRf0NvSdIjQ3Le1QGz8kNGBk7jgNHtNguvXRwmgs,557
44
+ nlbone/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
+ nlbone/interfaces/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ nlbone/interfaces/api/exception_handlers.py,sha256=vxNEBgAaQygLgAz1UNt3wHj0SdCJOwtLOv_BwTfir3o,4050
47
+ nlbone/interfaces/api/exceptions.py,sha256=6zWkMnmNGaSa3Myk3MxPCFje0yWWDcbqivIeOKxZuhs,2258
48
+ nlbone/interfaces/api/routers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
+ nlbone/interfaces/api/schemas.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
+ nlbone/interfaces/api/dependencies/__init__.py,sha256=rnYRrFVZCfICQrp_PVFlzNg3BeC57yM08wn2DbOHCfk,359
51
+ nlbone/interfaces/api/dependencies/async_auth.py,sha256=bfxgBXhp29WqevjTG4jrdPNR-75APm4jKyHdOOtxnp4,1825
52
+ nlbone/interfaces/api/dependencies/auth.py,sha256=VcWnEipQr4dqhzGbP0G9a5nJdplnpFG3wm_NlDCb8z4,1765
53
+ nlbone/interfaces/api/dependencies/db.py,sha256=DGX_hGVrPRnRIuhMnirJZvKNyj1OLC_hQSIrA9NVnNw,468
54
+ nlbone/interfaces/api/dependencies/uow.py,sha256=crV9mu4LlmJ0JI1uzNYkZX2VJUjQ6hWvxyXqleZL_ak,1183
55
+ nlbone/interfaces/api/middleware/__init__.py,sha256=zbX2vaEAfxRMIYwO2MVY_2O6bqG5H9o7HqGpX14U3Is,158
56
+ nlbone/interfaces/api/middleware/access_log.py,sha256=vIkxxxfy2HcjqqKb8XCfGCcSrivAC8u6ie75FMq5x-U,1032
57
+ nlbone/interfaces/api/middleware/add_request_context.py,sha256=av-qs0biOYuF9R6RJOo2eYsFqDL9WRYWcjVakFhbt-w,1834
58
+ nlbone/interfaces/api/middleware/authentication.py,sha256=ze7vCm492QsX9nPL6A-PqZCmC1C5ZgUE-OWI6fCLpsU,1809
59
+ nlbone/interfaces/api/pagination/__init__.py,sha256=sWKKQFa2Z-1SlprQOqImOa2c9exq4wueKpUL_9QM7wc,417
60
+ nlbone/interfaces/api/pagination/offset_base.py,sha256=B6rHxzDsxQbm-d2snM6tjgnhWyZw7zvs7fcehV0gpa0,3621
61
+ nlbone/interfaces/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
+ nlbone/interfaces/cli/init_db.py,sha256=EehZEsMeyR6vA4WvM6sAZ-IRhyiJZdrWBaYiptkJVdc,482
63
+ nlbone/interfaces/cli/main.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
+ nlbone/interfaces/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
+ nlbone/interfaces/jobs/sync_tokens.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
+ nlbone/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
+ nlbone/utils/context.py,sha256=MmclJ24BG2uvSTg1IK7J-Da9BhVFDQ5ag4Ggs2FF1_w,1600
68
+ nlbone/utils/time.py,sha256=0v7TpTglIo1BfwErceXbnFOu6XExNqTQELDXzxLdnAg,103
69
+ nlbone-0.4.1.dist-info/METADATA,sha256=byHqPsOWgE3I5pn0hJjszvG2KSCZFVfAxk7ZuM_4rAE,1979
70
+ nlbone-0.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
71
+ nlbone-0.4.1.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
+ nlbone-0.4.1.dist-info/RECORD,,