nexo-schemas 0.0.16__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.
- nexo/schemas/__init__.py +0 -0
- nexo/schemas/application.py +292 -0
- nexo/schemas/connection.py +134 -0
- nexo/schemas/data.py +27 -0
- nexo/schemas/document.py +237 -0
- nexo/schemas/error/__init__.py +476 -0
- nexo/schemas/error/constants.py +50 -0
- nexo/schemas/error/descriptor.py +354 -0
- nexo/schemas/error/enums.py +40 -0
- nexo/schemas/error/metadata.py +15 -0
- nexo/schemas/error/spec.py +312 -0
- nexo/schemas/exception/__init__.py +0 -0
- nexo/schemas/exception/exc.py +911 -0
- nexo/schemas/exception/factory.py +1928 -0
- nexo/schemas/exception/handlers.py +110 -0
- nexo/schemas/google.py +14 -0
- nexo/schemas/key/__init__.py +0 -0
- nexo/schemas/key/rsa.py +131 -0
- nexo/schemas/metadata.py +21 -0
- nexo/schemas/mixins/__init__.py +0 -0
- nexo/schemas/mixins/filter.py +140 -0
- nexo/schemas/mixins/general.py +65 -0
- nexo/schemas/mixins/hierarchy.py +19 -0
- nexo/schemas/mixins/identity.py +387 -0
- nexo/schemas/mixins/parameter.py +50 -0
- nexo/schemas/mixins/service.py +40 -0
- nexo/schemas/mixins/sort.py +111 -0
- nexo/schemas/mixins/timestamp.py +192 -0
- nexo/schemas/model.py +240 -0
- nexo/schemas/operation/__init__.py +0 -0
- nexo/schemas/operation/action/__init__.py +9 -0
- nexo/schemas/operation/action/base.py +14 -0
- nexo/schemas/operation/action/resource.py +371 -0
- nexo/schemas/operation/action/status.py +8 -0
- nexo/schemas/operation/action/system.py +6 -0
- nexo/schemas/operation/action/websocket.py +6 -0
- nexo/schemas/operation/base.py +289 -0
- nexo/schemas/operation/constants.py +18 -0
- nexo/schemas/operation/context.py +68 -0
- nexo/schemas/operation/dependency.py +26 -0
- nexo/schemas/operation/enums.py +168 -0
- nexo/schemas/operation/extractor.py +36 -0
- nexo/schemas/operation/mixins.py +53 -0
- nexo/schemas/operation/request.py +1066 -0
- nexo/schemas/operation/resource.py +839 -0
- nexo/schemas/operation/system.py +55 -0
- nexo/schemas/operation/websocket.py +55 -0
- nexo/schemas/pagination.py +67 -0
- nexo/schemas/parameter.py +60 -0
- nexo/schemas/payload.py +116 -0
- nexo/schemas/resource.py +64 -0
- nexo/schemas/response.py +1041 -0
- nexo/schemas/security/__init__.py +0 -0
- nexo/schemas/security/api_key.py +63 -0
- nexo/schemas/security/authentication.py +848 -0
- nexo/schemas/security/authorization.py +922 -0
- nexo/schemas/security/enums.py +32 -0
- nexo/schemas/security/impersonation.py +179 -0
- nexo/schemas/security/token.py +402 -0
- nexo/schemas/security/types.py +17 -0
- nexo/schemas/success/__init__.py +0 -0
- nexo/schemas/success/descriptor.py +100 -0
- nexo/schemas/success/enums.py +23 -0
- nexo/schemas/user_agent.py +46 -0
- nexo_schemas-0.0.16.dist-info/METADATA +87 -0
- nexo_schemas-0.0.16.dist-info/RECORD +69 -0
- nexo_schemas-0.0.16.dist-info/WHEEL +5 -0
- nexo_schemas-0.0.16.dist-info/licenses/LICENSE +21 -0
- nexo_schemas-0.0.16.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field
|
|
2
|
+
from typing import Generic
|
|
3
|
+
from nexo.types.dict import OptStrToAnyDict
|
|
4
|
+
from nexo.types.enum import StrEnumT
|
|
5
|
+
from .enums import (
|
|
6
|
+
Origin as OriginEnum,
|
|
7
|
+
Layer as LayerEnum,
|
|
8
|
+
Target as TargetEnum,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Component(BaseModel, Generic[StrEnumT]):
|
|
13
|
+
type: StrEnumT = Field(..., description="Component's type")
|
|
14
|
+
details: OptStrToAnyDict = Field(None, description="Component's details")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Origin(Component[OriginEnum]):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class OriginMixin(BaseModel):
|
|
22
|
+
origin: Origin = Field(..., description="Operation's origin")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Layer(Component[LayerEnum]):
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class LayerMixin(BaseModel):
|
|
30
|
+
layer: Layer = Field(..., description="Operation's layer")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Target(Component[TargetEnum]):
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TargetMixin(BaseModel):
|
|
38
|
+
target: Target = Field(..., description="Operation's target")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Context(TargetMixin, LayerMixin, OriginMixin):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ContextMixin(BaseModel):
|
|
46
|
+
context: Context = Field(..., description="Operation's context")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
UTILITY_OPERATION_CONTEXT = Context(
|
|
50
|
+
origin=Origin(type=OriginEnum.UTILITY, details=None),
|
|
51
|
+
layer=Layer(type=LayerEnum.INTERNAL, details=None),
|
|
52
|
+
target=Target(type=TargetEnum.INTERNAL, details=None),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def generate(
|
|
57
|
+
origin: OriginEnum,
|
|
58
|
+
layer: LayerEnum,
|
|
59
|
+
target: TargetEnum = TargetEnum.INTERNAL,
|
|
60
|
+
origin_details: OptStrToAnyDict = None,
|
|
61
|
+
layer_details: OptStrToAnyDict = None,
|
|
62
|
+
target_details: OptStrToAnyDict = None,
|
|
63
|
+
) -> Context:
|
|
64
|
+
return Context(
|
|
65
|
+
origin=Origin(type=origin, details=origin_details),
|
|
66
|
+
layer=Layer(type=layer, details=layer_details),
|
|
67
|
+
target=Target(type=target, details=target_details),
|
|
68
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from fastapi import Header
|
|
2
|
+
from fastapi.requests import HTTPConnection
|
|
3
|
+
from typing import Callable
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
from nexo.enums.connection import Header as HeaderEnum
|
|
6
|
+
from nexo.types.uuid import OptUUID
|
|
7
|
+
from .enums import IdSource
|
|
8
|
+
from .extractor import extract_operation_id
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_operation_id(
|
|
12
|
+
source: IdSource = IdSource.STATE, *, generate: bool = False
|
|
13
|
+
) -> Callable[..., UUID]:
|
|
14
|
+
|
|
15
|
+
def dependency(
|
|
16
|
+
conn: HTTPConnection,
|
|
17
|
+
# the following operation_id is for documentation purpose only
|
|
18
|
+
_operation_id: OptUUID = Header(
|
|
19
|
+
None,
|
|
20
|
+
alias=HeaderEnum.X_OPERATION_ID.value,
|
|
21
|
+
description="Operation's ID",
|
|
22
|
+
),
|
|
23
|
+
) -> UUID:
|
|
24
|
+
return extract_operation_id(source, conn=conn, generate=generate)
|
|
25
|
+
|
|
26
|
+
return dependency
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
from typing import TypeVar
|
|
3
|
+
from nexo.types.string import ListOfStrs
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class IdSource(StrEnum):
|
|
7
|
+
HEADER = "header"
|
|
8
|
+
STATE = "state"
|
|
9
|
+
|
|
10
|
+
@classmethod
|
|
11
|
+
def choices(cls) -> ListOfStrs:
|
|
12
|
+
return [e.value for e in cls]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class OperationType(StrEnum):
|
|
16
|
+
RESOURCE = "resource"
|
|
17
|
+
REQUEST = "request"
|
|
18
|
+
SYSTEM = "system"
|
|
19
|
+
WEBSOCKET = "websocket"
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def choices(cls) -> ListOfStrs:
|
|
23
|
+
return [e.value for e in cls]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
OptOperationType = OperationType | None
|
|
27
|
+
ListOfOperationTypes = list[OperationType]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class SystemOperationType(StrEnum):
|
|
31
|
+
BACKGROUND_JOB = "background_job"
|
|
32
|
+
CONFIGURATION_UPDATE = "configuration_update"
|
|
33
|
+
CRON_JOB = "cron_job"
|
|
34
|
+
DATABASE_CONNECTION = "database_connection"
|
|
35
|
+
DISPOSAL = "disposal"
|
|
36
|
+
HEALTH_CHECK = "health_check"
|
|
37
|
+
HEARTBEAT = "heartbeat"
|
|
38
|
+
METRIC_REPORT = "metric_report"
|
|
39
|
+
INITIALIZATION = "initialization"
|
|
40
|
+
STARTUP = "startup"
|
|
41
|
+
SHUTDOWN = "shutdown"
|
|
42
|
+
SYSTEM_ALERT = "system_alert"
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def choices(cls) -> ListOfStrs:
|
|
46
|
+
return [e.value for e in cls]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
OptSystemOperationType = SystemOperationType | None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class WebSocketOperationType(StrEnum):
|
|
53
|
+
CONNECT = "connect"
|
|
54
|
+
DISCONNECT = "disconnect"
|
|
55
|
+
ERROR = "error"
|
|
56
|
+
RECEIVE = "receive"
|
|
57
|
+
SEND = "send"
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def choices(cls) -> ListOfStrs:
|
|
61
|
+
return [e.value for e in cls]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
OptWebSocketOperationType = WebSocketOperationType | None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ResourceOperationType(StrEnum):
|
|
68
|
+
CREATE = "create"
|
|
69
|
+
READ = "read"
|
|
70
|
+
UPDATE = "update"
|
|
71
|
+
DELETE = "delete"
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def choices(cls) -> ListOfStrs:
|
|
75
|
+
return [e.value for e in cls]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
ResourceOperationTypeT = TypeVar("ResourceOperationTypeT", bound=ResourceOperationType)
|
|
79
|
+
OptResourceOperationType = ResourceOperationType | None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ResourceOperationUpdateType(StrEnum):
|
|
83
|
+
DATA = "data"
|
|
84
|
+
STATUS = "status"
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def choices(cls) -> ListOfStrs:
|
|
88
|
+
return [e.value for e in cls]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
OptResourceOperationUpdateType = ResourceOperationUpdateType | None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class ResourceOperationDataUpdateType(StrEnum):
|
|
95
|
+
FULL = "full"
|
|
96
|
+
PARTIAL = "partial"
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def choices(cls) -> ListOfStrs:
|
|
100
|
+
return [e.value for e in cls]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
OptResourceOperationDataUpdateType = ResourceOperationDataUpdateType | None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class ResourceOperationStatusUpdateType(StrEnum):
|
|
107
|
+
ACTIVATE = "activate"
|
|
108
|
+
DEACTIVATE = "deactivate"
|
|
109
|
+
RESTORE = "restore"
|
|
110
|
+
DELETE = "delete"
|
|
111
|
+
|
|
112
|
+
@classmethod
|
|
113
|
+
def choices(cls) -> ListOfStrs:
|
|
114
|
+
return [e.value for e in cls]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
OptResourceOperationStatusUpdateType = ResourceOperationStatusUpdateType | None
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class Origin(StrEnum):
|
|
121
|
+
SERVICE = "service"
|
|
122
|
+
CLIENT = "client"
|
|
123
|
+
UTILITY = "utility"
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def choices(cls) -> ListOfStrs:
|
|
127
|
+
return [e.value for e in cls]
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
OptOrigin = Origin | None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class Layer(StrEnum):
|
|
134
|
+
INFRASTRUCTURE = "infrastructure"
|
|
135
|
+
CONFIGURATION = "configuration"
|
|
136
|
+
UTILITY = "utility"
|
|
137
|
+
MIDDLEWARE = "middleware"
|
|
138
|
+
CONTROLLER = "controller"
|
|
139
|
+
SERVICE = "service"
|
|
140
|
+
REPOSITORY = "repository"
|
|
141
|
+
INTERNAL = "internal"
|
|
142
|
+
OTHER = "other"
|
|
143
|
+
|
|
144
|
+
@classmethod
|
|
145
|
+
def choices(cls) -> ListOfStrs:
|
|
146
|
+
return [e.value for e in cls]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
OptLayer = Layer | None
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class Target(StrEnum):
|
|
153
|
+
MONITORING = "monitoring"
|
|
154
|
+
CACHE = "cache"
|
|
155
|
+
CONTROLLER = "controller"
|
|
156
|
+
DATABASE = "database"
|
|
157
|
+
INTERNAL = "internal"
|
|
158
|
+
MICROSERVICE = "microservice"
|
|
159
|
+
SERVICE = "service"
|
|
160
|
+
REPOSITORY = "repository"
|
|
161
|
+
THIRD_PARTY = "third_party"
|
|
162
|
+
|
|
163
|
+
@classmethod
|
|
164
|
+
def choices(cls) -> ListOfStrs:
|
|
165
|
+
return [e.value for e in cls]
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
OptLayer = Layer | None
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from fastapi import status, HTTPException
|
|
2
|
+
from fastapi.requests import HTTPConnection
|
|
3
|
+
from uuid import UUID, uuid4
|
|
4
|
+
from nexo.enums.connection import Header
|
|
5
|
+
from .enums import IdSource
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def extract_operation_id(
|
|
9
|
+
source: IdSource = IdSource.STATE, *, conn: HTTPConnection, generate: bool = False
|
|
10
|
+
) -> UUID:
|
|
11
|
+
if source is IdSource.HEADER:
|
|
12
|
+
operation_id = conn.headers.get(Header.X_OPERATION_ID.value, None)
|
|
13
|
+
try:
|
|
14
|
+
operation_id = UUID(operation_id)
|
|
15
|
+
except Exception:
|
|
16
|
+
pass
|
|
17
|
+
elif source is IdSource.STATE:
|
|
18
|
+
operation_id = getattr(conn.state, "operation_id", None)
|
|
19
|
+
if operation_id is not None and not isinstance(operation_id, UUID):
|
|
20
|
+
raise HTTPException(
|
|
21
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
22
|
+
detail=f"Invalid operation id: {operation_id}",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
if operation_id is not None:
|
|
26
|
+
return operation_id
|
|
27
|
+
|
|
28
|
+
if generate:
|
|
29
|
+
operation_id = uuid4()
|
|
30
|
+
conn.state.operation_id = operation_id
|
|
31
|
+
return operation_id
|
|
32
|
+
|
|
33
|
+
raise HTTPException(
|
|
34
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
35
|
+
detail="Unable to determine operation_id",
|
|
36
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
from pydantic import BaseModel, Field, model_validator
|
|
3
|
+
from typing import Annotated, Self
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
from ..mixins.identity import UUIDId
|
|
6
|
+
from ..mixins.timestamp import ExecutionTimestamp, CompletionTimestamp, Duration
|
|
7
|
+
from .enums import OperationType as OperationTypeEnum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Id(UUIDId[UUID]):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class OperationType(BaseModel):
|
|
15
|
+
type: Annotated[OperationTypeEnum, Field(..., description="Operation's type")]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Timestamp(
|
|
19
|
+
Duration[float],
|
|
20
|
+
CompletionTimestamp[datetime],
|
|
21
|
+
ExecutionTimestamp[datetime],
|
|
22
|
+
):
|
|
23
|
+
duration: Annotated[float, Field(0.0, ge=0.0, description="Duration")] = 0.0
|
|
24
|
+
|
|
25
|
+
@model_validator(mode="after")
|
|
26
|
+
def calculate_duration(self) -> Self:
|
|
27
|
+
self.duration = (self.completed_at - self.executed_at).total_seconds()
|
|
28
|
+
return self
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def now(cls) -> "Timestamp":
|
|
32
|
+
now = datetime.now(tz=timezone.utc)
|
|
33
|
+
return cls(executed_at=now, completed_at=now, duration=0)
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def completed_now(cls, executed_at: datetime) -> "Timestamp":
|
|
37
|
+
completed_at = datetime.now(tz=timezone.utc)
|
|
38
|
+
return cls(
|
|
39
|
+
executed_at=executed_at,
|
|
40
|
+
completed_at=completed_at,
|
|
41
|
+
duration=(completed_at - executed_at).total_seconds(),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
OptTimestamp = Timestamp | None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class TimestampMixin(BaseModel):
|
|
49
|
+
timestamp: Annotated[Timestamp, Field(..., description="Operation's timestamp")]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Summary(BaseModel):
|
|
53
|
+
summary: Annotated[str, Field(..., description="Operation's summary")]
|