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.
Files changed (69) hide show
  1. nexo/schemas/__init__.py +0 -0
  2. nexo/schemas/application.py +292 -0
  3. nexo/schemas/connection.py +134 -0
  4. nexo/schemas/data.py +27 -0
  5. nexo/schemas/document.py +237 -0
  6. nexo/schemas/error/__init__.py +476 -0
  7. nexo/schemas/error/constants.py +50 -0
  8. nexo/schemas/error/descriptor.py +354 -0
  9. nexo/schemas/error/enums.py +40 -0
  10. nexo/schemas/error/metadata.py +15 -0
  11. nexo/schemas/error/spec.py +312 -0
  12. nexo/schemas/exception/__init__.py +0 -0
  13. nexo/schemas/exception/exc.py +911 -0
  14. nexo/schemas/exception/factory.py +1928 -0
  15. nexo/schemas/exception/handlers.py +110 -0
  16. nexo/schemas/google.py +14 -0
  17. nexo/schemas/key/__init__.py +0 -0
  18. nexo/schemas/key/rsa.py +131 -0
  19. nexo/schemas/metadata.py +21 -0
  20. nexo/schemas/mixins/__init__.py +0 -0
  21. nexo/schemas/mixins/filter.py +140 -0
  22. nexo/schemas/mixins/general.py +65 -0
  23. nexo/schemas/mixins/hierarchy.py +19 -0
  24. nexo/schemas/mixins/identity.py +387 -0
  25. nexo/schemas/mixins/parameter.py +50 -0
  26. nexo/schemas/mixins/service.py +40 -0
  27. nexo/schemas/mixins/sort.py +111 -0
  28. nexo/schemas/mixins/timestamp.py +192 -0
  29. nexo/schemas/model.py +240 -0
  30. nexo/schemas/operation/__init__.py +0 -0
  31. nexo/schemas/operation/action/__init__.py +9 -0
  32. nexo/schemas/operation/action/base.py +14 -0
  33. nexo/schemas/operation/action/resource.py +371 -0
  34. nexo/schemas/operation/action/status.py +8 -0
  35. nexo/schemas/operation/action/system.py +6 -0
  36. nexo/schemas/operation/action/websocket.py +6 -0
  37. nexo/schemas/operation/base.py +289 -0
  38. nexo/schemas/operation/constants.py +18 -0
  39. nexo/schemas/operation/context.py +68 -0
  40. nexo/schemas/operation/dependency.py +26 -0
  41. nexo/schemas/operation/enums.py +168 -0
  42. nexo/schemas/operation/extractor.py +36 -0
  43. nexo/schemas/operation/mixins.py +53 -0
  44. nexo/schemas/operation/request.py +1066 -0
  45. nexo/schemas/operation/resource.py +839 -0
  46. nexo/schemas/operation/system.py +55 -0
  47. nexo/schemas/operation/websocket.py +55 -0
  48. nexo/schemas/pagination.py +67 -0
  49. nexo/schemas/parameter.py +60 -0
  50. nexo/schemas/payload.py +116 -0
  51. nexo/schemas/resource.py +64 -0
  52. nexo/schemas/response.py +1041 -0
  53. nexo/schemas/security/__init__.py +0 -0
  54. nexo/schemas/security/api_key.py +63 -0
  55. nexo/schemas/security/authentication.py +848 -0
  56. nexo/schemas/security/authorization.py +922 -0
  57. nexo/schemas/security/enums.py +32 -0
  58. nexo/schemas/security/impersonation.py +179 -0
  59. nexo/schemas/security/token.py +402 -0
  60. nexo/schemas/security/types.py +17 -0
  61. nexo/schemas/success/__init__.py +0 -0
  62. nexo/schemas/success/descriptor.py +100 -0
  63. nexo/schemas/success/enums.py +23 -0
  64. nexo/schemas/user_agent.py +46 -0
  65. nexo_schemas-0.0.16.dist-info/METADATA +87 -0
  66. nexo_schemas-0.0.16.dist-info/RECORD +69 -0
  67. nexo_schemas-0.0.16.dist-info/WHEEL +5 -0
  68. nexo_schemas-0.0.16.dist-info/licenses/LICENSE +21 -0
  69. 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")]