nlbone 0.6.12__tar.gz → 0.6.14__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.
- {nlbone-0.6.12 → nlbone-0.6.14}/PKG-INFO +1 -1
- {nlbone-0.6.12 → nlbone-0.6.14}/pyproject.toml +1 -1
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/auth/keycloak.py +2 -2
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/postgres/query_builder.py +12 -15
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/http_clients/uploadchi/uploadchi.py +15 -14
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/percolation/connection.py +3 -1
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/container.py +8 -12
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/pagination/offset_base.py +16 -14
- nlbone-0.6.14/src/nlbone/interfaces/api/schema/__init__.py +2 -0
- nlbone-0.6.14/src/nlbone/interfaces/api/schema/adaptive_schema.py +78 -0
- nlbone-0.6.14/src/nlbone/interfaces/api/schema/base_response_model.py +5 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/.gitignore +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/LICENSE +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/README.md +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/auth/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/auth/token_provider.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/cache/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/cache/async_redis.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/cache/memory.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/cache/pubsub_listener.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/cache/redis.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/postgres/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/postgres/audit.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/postgres/base.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/postgres/engine.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/postgres/repository.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/postgres/schema.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/postgres/uow.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/redis/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/db/redis/client.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/http_clients/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/http_clients/pricing/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/http_clients/pricing/pricing_service.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/http_clients/uploadchi/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/http_clients/uploadchi/uploadchi_async.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/messaging/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/messaging/event_bus.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/messaging/redis.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/percolation/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/config/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/config/logging.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/config/settings.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/application/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/application/base_worker.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/application/events.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/application/services/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/application/services.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/application/use_case.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/domain/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/domain/base.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/domain/events.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/domain/models.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/ports/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/ports/auth.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/ports/cache.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/ports/event_bus.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/ports/files.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/ports/messaging.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/ports/repo.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/core/ports/uow.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/dependencies/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/dependencies/async_auth.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/dependencies/auth.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/dependencies/db.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/dependencies/uow.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/exception_handlers.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/exceptions.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/middleware/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/middleware/access_log.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/middleware/add_request_context.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/middleware/authentication.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/pagination/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/routers.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/api/schemas.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/cli/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/cli/init_db.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/cli/main.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/jobs/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/interfaces/jobs/sync_tokens.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/types.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/utils/__init__.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/utils/cache.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/utils/cache_keys.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/utils/cache_registry.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/utils/context.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/utils/http.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/utils/redactor.py +0 -0
- {nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/utils/time.py +0 -0
|
@@ -36,7 +36,7 @@ class KeycloakAuthService(AuthService):
|
|
|
36
36
|
realm_name=s.KEYCLOAK_REALM_NAME,
|
|
37
37
|
client_secret_key=s.KEYCLOAK_CLIENT_SECRET.get_secret_value().strip(),
|
|
38
38
|
)
|
|
39
|
-
self.bypass = s.ENV !=
|
|
39
|
+
self.bypass = s.ENV != "prod"
|
|
40
40
|
|
|
41
41
|
def has_access(self, token, permissions):
|
|
42
42
|
if self.bypass:
|
|
@@ -145,4 +145,4 @@ class KeycloakAuthService(AuthService):
|
|
|
145
145
|
|
|
146
146
|
@functools.lru_cache(maxsize=1)
|
|
147
147
|
def get_auth_service() -> KeycloakAuthService:
|
|
148
|
-
return KeycloakAuthService()
|
|
148
|
+
return KeycloakAuthService()
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from typing import Any, Callable, Optional, Sequence, Type, Union
|
|
2
2
|
|
|
3
|
-
from sqlalchemy import
|
|
3
|
+
from sqlalchemy import and_, asc, case, desc, literal, or_
|
|
4
4
|
from sqlalchemy.dialects.postgresql import ENUM as PGEnum
|
|
5
|
-
from sqlalchemy.orm import Query, Session
|
|
5
|
+
from sqlalchemy.orm import Query, Session, aliased
|
|
6
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
6
7
|
from sqlalchemy.orm.interfaces import LoaderOption
|
|
8
|
+
from sqlalchemy.orm.relationships import RelationshipProperty
|
|
7
9
|
from sqlalchemy.sql.sqltypes import (
|
|
8
10
|
BigInteger,
|
|
9
11
|
Boolean,
|
|
@@ -28,12 +30,6 @@ class _InvalidEnum(Exception):
|
|
|
28
30
|
pass
|
|
29
31
|
|
|
30
32
|
|
|
31
|
-
from sqlalchemy.orm import aliased
|
|
32
|
-
from sqlalchemy.inspection import inspect
|
|
33
|
-
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
34
|
-
from sqlalchemy.orm.relationships import RelationshipProperty
|
|
35
|
-
|
|
36
|
-
|
|
37
33
|
def _resolve_column_and_joins(entity, query, field_path: str, join_cache: dict[str, Any]):
|
|
38
34
|
parts = [p for p in field_path.split(".") if p]
|
|
39
35
|
if not parts:
|
|
@@ -201,6 +197,7 @@ def _apply_filters(pagination, entity, query):
|
|
|
201
197
|
return v
|
|
202
198
|
|
|
203
199
|
try:
|
|
200
|
+
|
|
204
201
|
def _use_ilike(v) -> bool:
|
|
205
202
|
if op_hint == "ilike":
|
|
206
203
|
return True
|
|
@@ -304,13 +301,13 @@ def _serialize_item(item: Any, output_cls: OutputType) -> Any:
|
|
|
304
301
|
|
|
305
302
|
|
|
306
303
|
def get_paginated_response(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
304
|
+
pagination,
|
|
305
|
+
entity,
|
|
306
|
+
session: Session,
|
|
307
|
+
*,
|
|
308
|
+
with_count: bool = True,
|
|
309
|
+
output_cls: Optional[Type] = None,
|
|
310
|
+
eager_options: Optional[Sequence[LoaderOption]] = None,
|
|
314
311
|
) -> dict:
|
|
315
312
|
query = session.query(entity)
|
|
316
313
|
if eager_options:
|
|
@@ -35,11 +35,11 @@ def _filename_from_cd(cd: str | None, fallback: str) -> str:
|
|
|
35
35
|
|
|
36
36
|
class UploadchiClient(FileServicePort):
|
|
37
37
|
def __init__(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
self,
|
|
39
|
+
token_provider: ClientTokenProvider | None = None,
|
|
40
|
+
base_url: Optional[str] = None,
|
|
41
|
+
timeout_seconds: Optional[float] = None,
|
|
42
|
+
client: httpx.Client | None = None,
|
|
43
43
|
) -> None:
|
|
44
44
|
s = get_settings()
|
|
45
45
|
self._base_url = normalize_https_base(base_url or str(s.UPLOADCHI_BASE_URL))
|
|
@@ -51,7 +51,7 @@ class UploadchiClient(FileServicePort):
|
|
|
51
51
|
self._client.close()
|
|
52
52
|
|
|
53
53
|
def upload_file(
|
|
54
|
-
|
|
54
|
+
self, file_bytes: bytes, filename: str, params: dict[str, Any] | None = None, token: str | None = None
|
|
55
55
|
) -> dict:
|
|
56
56
|
tok = _resolve_token(token)
|
|
57
57
|
files = {"file": (filename, file_bytes)}
|
|
@@ -84,12 +84,12 @@ class UploadchiClient(FileServicePort):
|
|
|
84
84
|
raise UploadchiError(r.status_code, r.text)
|
|
85
85
|
|
|
86
86
|
def list_files(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
self,
|
|
88
|
+
limit: int = 10,
|
|
89
|
+
offset: int = 0,
|
|
90
|
+
filters: dict[str, Any] | None = None,
|
|
91
|
+
sort: list[tuple[str, str]] | None = None,
|
|
92
|
+
token: str | None = None,
|
|
93
93
|
) -> dict:
|
|
94
94
|
tok = _resolve_token(token)
|
|
95
95
|
q = build_list_query(limit, offset, filters, sort)
|
|
@@ -116,7 +116,8 @@ class UploadchiClient(FileServicePort):
|
|
|
116
116
|
|
|
117
117
|
def delete_file(self, file_id: str, token: str | None = None) -> None:
|
|
118
118
|
tok = _resolve_token(token)
|
|
119
|
-
r = self._client.delete(
|
|
120
|
-
|
|
119
|
+
r = self._client.delete(
|
|
120
|
+
f"{self._base_url}/{file_id}", headers=auth_headers(tok or self._token_provider.get_access_token())
|
|
121
|
+
)
|
|
121
122
|
if r.status_code not in (204, 200):
|
|
122
123
|
raise UploadchiError(r.status_code, r.text)
|
|
@@ -9,6 +9,8 @@ def get_es_client():
|
|
|
9
9
|
es = Elasticsearch(
|
|
10
10
|
setting.ELASTIC_PERCOLATE_URL,
|
|
11
11
|
basic_auth=(setting.ELASTIC_PERCOLATE_USER, setting.ELASTIC_PERCOLATE_PASS.get_secret_value().strip()),
|
|
12
|
-
http_compress=True,
|
|
12
|
+
http_compress=True,
|
|
13
|
+
max_retries=2,
|
|
14
|
+
retry_on_timeout=True,
|
|
13
15
|
)
|
|
14
16
|
return es
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Dict, Optional
|
|
4
4
|
|
|
5
5
|
from dependency_injector import containers, providers
|
|
6
|
+
from pydantic_settings import BaseSettings
|
|
6
7
|
|
|
7
8
|
from nlbone.adapters.auth.keycloak import KeycloakAuthService
|
|
8
9
|
from nlbone.adapters.auth.token_provider import ClientTokenProvider
|
|
@@ -15,7 +16,6 @@ from nlbone.adapters.http_clients import PricingService
|
|
|
15
16
|
from nlbone.adapters.http_clients.uploadchi import UploadchiClient
|
|
16
17
|
from nlbone.adapters.http_clients.uploadchi.uploadchi_async import UploadchiAsyncClient
|
|
17
18
|
from nlbone.adapters.messaging import InMemoryEventBus
|
|
18
|
-
from nlbone.config.settings import Settings
|
|
19
19
|
from nlbone.core.ports import EventBusPort
|
|
20
20
|
from nlbone.core.ports.cache import AsyncCachePort, CachePort
|
|
21
21
|
from nlbone.core.ports.files import AsyncFileServicePort, FileServicePort
|
|
@@ -35,7 +35,7 @@ class Container(containers.DeclarativeContainer):
|
|
|
35
35
|
event_bus: providers.Singleton[EventBusPort] = providers.Singleton(InMemoryEventBus)
|
|
36
36
|
|
|
37
37
|
# --- Services ---
|
|
38
|
-
auth: providers.Singleton[KeycloakAuthService] = providers.Singleton(KeycloakAuthService
|
|
38
|
+
auth: providers.Singleton[KeycloakAuthService] = providers.Singleton(KeycloakAuthService)
|
|
39
39
|
token_provider = providers.Singleton(ClientTokenProvider, auth=auth, skew_seconds=30)
|
|
40
40
|
file_service: providers.Singleton[FileServicePort] = providers.Singleton(
|
|
41
41
|
UploadchiClient, token_provider=token_provider
|
|
@@ -60,15 +60,11 @@ class Container(containers.DeclarativeContainer):
|
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
def create_container(settings: Optional[
|
|
63
|
+
def create_container(settings: Optional[BaseSettings | Dict] = None) -> Container:
|
|
64
64
|
c = Container()
|
|
65
65
|
if settings is not None:
|
|
66
|
-
if isinstance(settings,
|
|
67
|
-
c.config.
|
|
68
|
-
elif
|
|
69
|
-
c.config.from_dict(settings
|
|
70
|
-
elif hasattr(settings, "dict"):
|
|
71
|
-
c.config.from_dict(settings.dict()) # Pydantic v1
|
|
72
|
-
elif isinstance(settings, Mapping):
|
|
73
|
-
c.config.from_dict(dict(settings))
|
|
66
|
+
if isinstance(settings, BaseSettings):
|
|
67
|
+
c.config.from_pydantic(settings)
|
|
68
|
+
elif isinstance(settings, Dict):
|
|
69
|
+
c.config.from_dict(settings)
|
|
74
70
|
return c
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from math import ceil
|
|
3
|
-
from typing import Any,
|
|
3
|
+
from typing import Any, List, Optional
|
|
4
4
|
|
|
5
5
|
from fastapi import Query
|
|
6
6
|
|
|
@@ -13,18 +13,20 @@ class PaginateRequest:
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
def __init__(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
self,
|
|
17
|
+
limit: int = 10,
|
|
18
|
+
offset: int = 0,
|
|
19
|
+
sort: Optional[str] = None,
|
|
20
|
+
filters: Optional[str] = Query(None, description="e.g. title:abc"),
|
|
21
|
+
include: Optional[str] = None,
|
|
22
22
|
) -> None:
|
|
23
23
|
self.limit = max(0, limit)
|
|
24
24
|
self.offset = max(0, offset)
|
|
25
25
|
self.sort = self._parse_sort(sort)
|
|
26
26
|
self.filters = self._parse_filters(filters or "")
|
|
27
|
-
self.include_ids: List[int] = ([int(x) for x in include.split(",") if x.strip().isdigit()] if include else [])[
|
|
27
|
+
self.include_ids: List[int] = ([int(x) for x in include.split(",") if x.strip().isdigit()] if include else [])[
|
|
28
|
+
:50
|
|
29
|
+
]
|
|
28
30
|
|
|
29
31
|
@staticmethod
|
|
30
32
|
def _parse_sort(sort_str: Optional[str]) -> list[dict[str, str]]:
|
|
@@ -83,12 +85,12 @@ class PaginateResponse:
|
|
|
83
85
|
"""
|
|
84
86
|
|
|
85
87
|
def __init__(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
self,
|
|
89
|
+
data: list[Any],
|
|
90
|
+
total_count: int | None,
|
|
91
|
+
limit: int,
|
|
92
|
+
offset: int,
|
|
93
|
+
use_data_key: bool = True,
|
|
92
94
|
) -> None:
|
|
93
95
|
self.data = data
|
|
94
96
|
self.total_count = total_count
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Any, List, Type, get_args, get_origin
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from nlbone.utils.context import current_request
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ResponsePreference(str, Enum):
|
|
11
|
+
minimal = "minimal"
|
|
12
|
+
lite = "lite"
|
|
13
|
+
full = "full"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AdaptiveSchemaBase(ABC):
|
|
17
|
+
@classmethod
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def minimal(cls) -> Type:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def lite(cls) -> Type:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def full(cls) -> Type:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def choose(cls, preference: ResponsePreference) -> Type:
|
|
34
|
+
if preference == ResponsePreference.minimal:
|
|
35
|
+
return cls.minimal()
|
|
36
|
+
elif preference == ResponsePreference.lite:
|
|
37
|
+
return cls.lite()
|
|
38
|
+
elif preference == ResponsePreference.full:
|
|
39
|
+
return cls.full()
|
|
40
|
+
return cls.lite()
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def serialize(cls, obj: Any, preference: ResponsePreference = None) -> Any:
|
|
44
|
+
if not preference:
|
|
45
|
+
preference = current_request().state.response_preference
|
|
46
|
+
|
|
47
|
+
schema = cls.choose(preference)
|
|
48
|
+
|
|
49
|
+
if isinstance(obj, list):
|
|
50
|
+
return [cls._recursive_serialize(schema, item) for item in obj]
|
|
51
|
+
|
|
52
|
+
return cls._recursive_serialize(schema, obj)
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def _recursive_serialize(cls, schema_cls: type[BaseModel], item: Any) -> dict:
|
|
56
|
+
# Create base dict from ORM model
|
|
57
|
+
raw_data = schema_cls.model_validate(item).model_dump()
|
|
58
|
+
|
|
59
|
+
# Check each field to see if it needs nested serialization
|
|
60
|
+
annotations = schema_cls.__annotations__
|
|
61
|
+
|
|
62
|
+
for field_name, field_type in annotations.items():
|
|
63
|
+
field_value = getattr(item, field_name, None)
|
|
64
|
+
|
|
65
|
+
if field_value is None:
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
# Check for nested AdaptiveSchemaBase (single object)
|
|
69
|
+
if isinstance(field_type, type) and issubclass(field_type, AdaptiveSchemaBase):
|
|
70
|
+
raw_data[field_name] = field_type.serialize(field_value)
|
|
71
|
+
|
|
72
|
+
# Check for list[AdaptiveSchemaBase]
|
|
73
|
+
elif get_origin(field_type) in (list, List):
|
|
74
|
+
sub_type = get_args(field_type)[0]
|
|
75
|
+
if isinstance(sub_type, type) and issubclass(sub_type, AdaptiveSchemaBase):
|
|
76
|
+
raw_data[field_name] = sub_type.serialize(field_value)
|
|
77
|
+
|
|
78
|
+
return raw_data
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nlbone-0.6.12 → nlbone-0.6.14}/src/nlbone/adapters/http_clients/uploadchi/uploadchi_async.py
RENAMED
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|