plexus-python-pulse-demeter 1.1.126__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 (31) hide show
  1. plexus/pulse/demeter/__init__.py +6 -0
  2. plexus/pulse/demeter/app/__init__.py +0 -0
  3. plexus/pulse/demeter/app/api/__init__.py +44 -0
  4. plexus/pulse/demeter/app/api/archive_internal_endpoints.py +316 -0
  5. plexus/pulse/demeter/app/api/archive_public_endpoints.py +255 -0
  6. plexus/pulse/demeter/app/api/dataset_internal_endpoints.py +1043 -0
  7. plexus/pulse/demeter/app/api/dataset_public_endpoints.py +2161 -0
  8. plexus/pulse/demeter/app/api/dataset_workflow_endpoints.py +532 -0
  9. plexus/pulse/demeter/app/api/tagging_endpoints.py +323 -0
  10. plexus/pulse/demeter/app/api/user_endpoints.py +78 -0
  11. plexus/pulse/demeter/app/core/__init__.py +0 -0
  12. plexus/pulse/demeter/app/core/database.py +43 -0
  13. plexus/pulse/demeter/app/core/vault.py +29 -0
  14. plexus/pulse/demeter/app/main.py +16 -0
  15. plexus/pulse/demeter/app/models/__init__.py +33 -0
  16. plexus/pulse/demeter/app/models/local.py +249 -0
  17. plexus/pulse/demeter/app/models/registry/__init__.py +112 -0
  18. plexus/pulse/demeter/app/models/registry/archive.py +529 -0
  19. plexus/pulse/demeter/app/models/registry/dataset.py +1531 -0
  20. plexus/pulse/demeter/app/models/registry/tagging.py +478 -0
  21. plexus/pulse/demeter/app/models/registry/user.py +79 -0
  22. plexus/pulse/demeter/tools/__init__.py +0 -0
  23. plexus/pulse/demeter/tools/main.py +306 -0
  24. plexus/pulse/demeter/utils/__init__.py +0 -0
  25. plexus/pulse/demeter/utils/config.py +25 -0
  26. plexus/pulse/demeter/utils/datautils.py +436 -0
  27. plexus_python_pulse_demeter-1.1.126.dist-info/METADATA +36 -0
  28. plexus_python_pulse_demeter-1.1.126.dist-info/RECORD +31 -0
  29. plexus_python_pulse_demeter-1.1.126.dist-info/WHEEL +5 -0
  30. plexus_python_pulse_demeter-1.1.126.dist-info/entry_points.txt +2 -0
  31. plexus_python_pulse_demeter-1.1.126.dist-info/top_level.txt +1 -0
@@ -0,0 +1,249 @@
1
+ import datetime
2
+ import uuid as py_uuid
3
+ from typing import Self
4
+
5
+ import pydantic as pdt
6
+ from plexus.common.utils.jsonutils import JsonType
7
+ from plexus.pulse.common.utils.datautils import (
8
+ validate_bag_name,
9
+ validate_colon_tag,
10
+ validate_dt_timezone,
11
+ validate_json_type_dump_size,
12
+ validate_slash_tag,
13
+ validate_snake_case,
14
+ validate_strict_relpath,
15
+ validate_user_name,
16
+ validate_vehicle_name,
17
+ )
18
+ from plexus.pulse.common.utils.jsonutils import json_datetime_encoder
19
+ from plexus.pulse.common.utils.ormutils import make_base_model
20
+ from sqlmodel import Field
21
+
22
+ __all__ = [
23
+ "LocalBase",
24
+ "DatasetMetafile",
25
+ "SampleMetafile",
26
+ "StandaloneDataset",
27
+ "StandaloneSample",
28
+ ]
29
+
30
+ LocalBase = make_base_model()
31
+
32
+
33
+ class DatasetMetafile(LocalBase):
34
+ name: str
35
+ description: str
36
+ contributor: str
37
+ tags: list[str] | None = Field(default=None)
38
+ props: JsonType
39
+
40
+ @pdt.field_validator("name", mode="after")
41
+ @classmethod
42
+ def validate_name(cls, v: str) -> str:
43
+ validate_snake_case(v)
44
+ return v
45
+
46
+ @pdt.field_validator("contributor", mode="after")
47
+ @classmethod
48
+ def validate_contributor(cls, v: str) -> str:
49
+ validate_user_name(v)
50
+ return v
51
+
52
+ @pdt.field_validator("tags", mode="after")
53
+ @classmethod
54
+ def validate_tags(cls, v: list[str] | None) -> list[str] | None:
55
+ for tag in (v or []):
56
+ validate_colon_tag(tag)
57
+ return v
58
+
59
+ @pdt.field_validator("props", mode="after")
60
+ @classmethod
61
+ def validate_props(cls, v: JsonType) -> JsonType:
62
+ validate_json_type_dump_size(v, 10000)
63
+ return v
64
+
65
+
66
+ class SampleMetafile(LocalBase):
67
+ layout_uuid: py_uuid.UUID | None = Field(default=None)
68
+ layout_name: str | None = Field(default=None)
69
+ bag_name: str
70
+ vehicle_name: str
71
+ begin_frame_dt: datetime.datetime
72
+ end_frame_dt: datetime.datetime
73
+ tags: list[str] | None = Field(default=None)
74
+ props: JsonType
75
+
76
+ @pdt.field_validator("layout_name", mode="after")
77
+ @classmethod
78
+ def validate_layout_name(cls, v: str | None) -> str | None:
79
+ if v is not None:
80
+ validate_slash_tag(v)
81
+ return v
82
+
83
+ @pdt.model_validator(mode="after")
84
+ def validate_layout_uuid_layout_name(self) -> Self:
85
+ if (self.layout_uuid is None) and (self.layout_name is None):
86
+ raise ValueError("either layout_uuid or layout_name must be provided")
87
+ return self
88
+
89
+ @pdt.field_validator("bag_name", mode="after")
90
+ @classmethod
91
+ def validate_bag_name(cls, v: str) -> str:
92
+ validate_bag_name(v)
93
+ return v
94
+
95
+ @pdt.field_validator("vehicle_name", mode="after")
96
+ @classmethod
97
+ def validate_vehicle_name(cls, v: str) -> str:
98
+ validate_vehicle_name(v)
99
+ return v
100
+
101
+ @pdt.field_validator("begin_frame_dt", mode="after")
102
+ @classmethod
103
+ def validate_begin_frame_dt(cls, v: datetime.datetime) -> datetime.datetime:
104
+ validate_dt_timezone(v)
105
+ return v
106
+
107
+ @pdt.field_validator("end_frame_dt", mode="after")
108
+ @classmethod
109
+ def validate_end_frame_dt(cls, v: datetime.datetime) -> datetime.datetime:
110
+ validate_dt_timezone(v)
111
+ return v
112
+
113
+ @pdt.model_validator(mode="after")
114
+ def validate_begin_frame_dt_end_frame_dt(self) -> Self:
115
+ if self.begin_frame_dt > self.end_frame_dt:
116
+ raise ValueError(
117
+ f"begin_frame_dt '{self.begin_frame_dt}' is greater than end_frame_dt '{self.end_frame_dt}'")
118
+ return self
119
+
120
+ @pdt.field_validator("tags", mode="after")
121
+ @classmethod
122
+ def validate_tags(cls, v: list[str] | None) -> list[str] | None:
123
+ for tag in (v or []):
124
+ validate_colon_tag(tag)
125
+ return v
126
+
127
+ @pdt.field_validator("props", mode="after")
128
+ @classmethod
129
+ def validate_props(cls, v: JsonType) -> JsonType:
130
+ validate_json_type_dump_size(v, 10000)
131
+ return v
132
+
133
+ @pdt.field_serializer("begin_frame_dt", mode="plain")
134
+ def serialize_begin_frame_dt(self, v: datetime.datetime) -> str:
135
+ return json_datetime_encoder(v)
136
+
137
+ @pdt.field_serializer("end_frame_dt", mode="plain")
138
+ def serialize_end_frame_dt(self, v: datetime.datetime) -> str:
139
+ return json_datetime_encoder(v)
140
+
141
+
142
+ class StandaloneDataset(LocalBase):
143
+ name: str
144
+ description: str
145
+ contributor: str
146
+ tags: list[str] | None = Field(default=None)
147
+ props: JsonType
148
+
149
+ @pdt.field_validator("name", mode="after")
150
+ @classmethod
151
+ def validate_name(cls, v: str) -> str:
152
+ validate_snake_case(v)
153
+ return v
154
+
155
+ @pdt.field_validator("contributor", mode="after")
156
+ @classmethod
157
+ def validate_contributor(cls, v: str) -> str:
158
+ validate_user_name(v)
159
+ return v
160
+
161
+ @pdt.field_validator("tags", mode="after")
162
+ @classmethod
163
+ def validate_tags(cls, v: list[str] | None) -> list[str] | None:
164
+ for tag in (v or []):
165
+ validate_colon_tag(tag)
166
+ return v
167
+
168
+ @pdt.field_validator("props", mode="after")
169
+ @classmethod
170
+ def validate_props(cls, v: JsonType) -> JsonType:
171
+ validate_json_type_dump_size(v, 10000)
172
+ return v
173
+
174
+
175
+ class StandaloneSample(LocalBase):
176
+ path: str
177
+ layout_uuid: py_uuid.UUID
178
+ bag_name: str
179
+ vehicle_name: str
180
+ begin_frame_dt: datetime.datetime
181
+ end_frame_dt: datetime.datetime
182
+ child_sample_paths: list[str] | None = Field(default=None)
183
+ tags: list[str] | None = Field(default=None)
184
+ props: JsonType
185
+
186
+ @pdt.field_validator("path", mode="after")
187
+ @classmethod
188
+ def validate_path(cls, v: str) -> str:
189
+ validate_strict_relpath(v)
190
+ return v
191
+
192
+ @pdt.field_validator("bag_name", mode="after")
193
+ @classmethod
194
+ def validate_bag_name(cls, v: str) -> str:
195
+ validate_bag_name(v)
196
+ return v
197
+
198
+ @pdt.field_validator("vehicle_name", mode="after")
199
+ @classmethod
200
+ def validate_vehicle_name(cls, v: str) -> str:
201
+ validate_vehicle_name(v)
202
+ return v
203
+
204
+ @pdt.field_validator("begin_frame_dt", mode="after")
205
+ @classmethod
206
+ def validate_begin_frame_dt(cls, v: datetime.datetime) -> datetime.datetime:
207
+ validate_dt_timezone(v)
208
+ return v
209
+
210
+ @pdt.field_validator("end_frame_dt", mode="after")
211
+ @classmethod
212
+ def validate_end_frame_dt(cls, v: datetime.datetime) -> datetime.datetime:
213
+ validate_dt_timezone(v)
214
+ return v
215
+
216
+ @pdt.model_validator(mode="after")
217
+ def validate_begin_frame_dt_end_frame_dt(self) -> Self:
218
+ if self.begin_frame_dt > self.end_frame_dt:
219
+ raise ValueError(
220
+ f"begin_frame_dt '{self.begin_frame_dt}' is greater than end_frame_dt '{self.end_frame_dt}'")
221
+ return self
222
+
223
+ @pdt.field_validator("child_sample_paths", mode="after")
224
+ @classmethod
225
+ def validate_child_sample_paths(cls, v: list[str] | None) -> list[str] | None:
226
+ for path in (v or []):
227
+ validate_strict_relpath(path)
228
+ return v
229
+
230
+ @pdt.field_validator("tags", mode="after")
231
+ @classmethod
232
+ def validate_tags(cls, v: list[str] | None) -> list[str] | None:
233
+ for tag in (v or []):
234
+ validate_colon_tag(tag)
235
+ return v
236
+
237
+ @pdt.field_validator("props", mode="after")
238
+ @classmethod
239
+ def validate_props(cls, v: JsonType) -> JsonType:
240
+ validate_json_type_dump_size(v, 10000)
241
+ return v
242
+
243
+ @pdt.field_serializer("begin_frame_dt", mode="plain")
244
+ def serialize_begin_frame_dt(self, v: datetime.datetime) -> str:
245
+ return json_datetime_encoder(v)
246
+
247
+ @pdt.field_serializer("end_frame_dt", mode="plain")
248
+ def serialize_end_frame_dt(self, v: datetime.datetime) -> str:
249
+ return json_datetime_encoder(v)
@@ -0,0 +1,112 @@
1
+ import enum
2
+ from typing import Self
3
+
4
+ import textcase
5
+ from plexus.common.utils.funcutils import singleton
6
+ from plexus.pulse.common.utils.ormutils import make_base_model
7
+
8
+ __all__ = [
9
+ "RegistryBase",
10
+ "JobStatusFlag",
11
+ ]
12
+
13
+ RegistryBase = make_base_model()
14
+ RegistryBase.metadata.schema = "pulse_demeter"
15
+ RegistryBase.model_config.update(dict(alias_generator=textcase.camel, populate_by_name=True))
16
+
17
+
18
+ class JobStatusFlag(enum.Flag):
19
+ """
20
+ Comprehensive job status bitflags.
21
+
22
+ Flags are grouped by functional categories with distinct bit ranges:
23
+ - progression: job lifecycle states (0x01 - 0x80)
24
+ - control: control/administrative requests (0x0100 - 0x8000)
25
+ - outcome: terminal outcomes (0x010000 - 0x800000)
26
+ """
27
+ # Progression / lifecycle (ongoing states)
28
+ Submitted = 0x01
29
+ Queued = 0x02
30
+ Scheduled = 0x04
31
+ Running = 0x08
32
+ Paused = 0x10
33
+ Retrying = 0x20
34
+
35
+ # Control / administrative
36
+ EarlyStopRequested = 0x02_00
37
+ CancelRequested = 0x04_00
38
+
39
+ # Terminal / outcome
40
+ Completed = 0x01_00_00
41
+ EarlyStopped = 0x02_00_00
42
+ Cancelled = 0x04_00_00
43
+ Timeout = 0x08_00_00
44
+ Failed = 0x10_00_00
45
+
46
+ # Composite helpers
47
+ Progressing = Submitted | Queued | Scheduled | Running | Paused | Retrying
48
+ Terminal = Completed | EarlyStopped | Cancelled | Timeout | Failed
49
+
50
+ @classmethod
51
+ @singleton
52
+ def progressing_states(cls) -> list[Self]:
53
+ return [
54
+ cls.Submitted,
55
+ cls.Queued,
56
+ cls.Scheduled,
57
+ cls.Running,
58
+ cls.Paused,
59
+ cls.Retrying,
60
+ ]
61
+
62
+ @classmethod
63
+ @singleton
64
+ def terminal_states(cls) -> list[Self]:
65
+ return [
66
+ cls.Completed,
67
+ cls.EarlyStopped,
68
+ cls.Cancelled,
69
+ cls.Timeout,
70
+ cls.Failed,
71
+ ]
72
+
73
+ @classmethod
74
+ @singleton
75
+ def transitions(cls) -> dict[Self, set[Self]]:
76
+ return {
77
+ cls.Submitted: {
78
+ cls.Queued,
79
+ cls.CancelRequested,
80
+ },
81
+ cls.Queued: {
82
+ cls.Scheduled,
83
+ cls.CancelRequested,
84
+ },
85
+ cls.Scheduled: {
86
+ cls.Running,
87
+ cls.CancelRequested,
88
+ },
89
+ cls.Running: {
90
+ cls.Paused,
91
+ cls.EarlyStopRequested,
92
+ cls.CancelRequested,
93
+ cls.Completed,
94
+ cls.Timeout,
95
+ cls.Failed,
96
+ },
97
+ cls.Paused: {
98
+ cls.Running,
99
+ cls.EarlyStopRequested,
100
+ cls.CancelRequested,
101
+ },
102
+ cls.Retrying: {
103
+ cls.Queued,
104
+ cls.CancelRequested,
105
+ },
106
+ cls.EarlyStopRequested: {
107
+ cls.EarlyStopped,
108
+ },
109
+ cls.CancelRequested: {
110
+ cls.Cancelled,
111
+ },
112
+ }