UncountablePythonSDK 0.0.79__py3-none-any.whl → 0.0.81__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.

Potentially problematic release.


This version of UncountablePythonSDK might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.79
3
+ Version: 0.0.81
4
4
  Summary: Uncountable SDK
5
5
  Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
6
6
  Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
@@ -23,7 +23,8 @@ examples/set_recipe_output_file_sdk.py,sha256=Lz1amqppnWTX83z-C090wCJ4hcKmCD3kb-
23
23
  examples/upload_files.py,sha256=tUfKFqiqwnw08OL5Y8_e4j5pSRhp94cFex8XTuVa_ig,487
24
24
  examples/integration-server/pyproject.toml,sha256=mB0uj-_Wo8WRmhdMwOwcdOB5lAhiW_8Kf-epMFrOq34,9133
25
25
  examples/integration-server/jobs/materials_auto/example_cron.py,sha256=7VVQ-UJsq3DbGpN3XPnorRVZYo-vCwbfSU3VVDluIzA,699
26
- examples/integration-server/jobs/materials_auto/profile.yaml,sha256=MiqT9AHWoFz-rcpAHfiFTXuCP-18DaFipUaceati0-0,365
26
+ examples/integration-server/jobs/materials_auto/example_wh.py,sha256=Hx5nonavOh2L3JykDpI5bPqPu8L1wwhwekTUfTRgq9g,479
27
+ examples/integration-server/jobs/materials_auto/profile.yaml,sha256=XlOXSRplMJ13T6900pv1wDKxeE9V1hZZTMuvup1MiBM,896
27
28
  pkgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
29
  pkgs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
30
  pkgs/argument_parser/__init__.py,sha256=JRfZkC0-q6axr8F5_TKrjSprJ7d7chfcPvf-iMQqFg0,447
@@ -41,7 +42,7 @@ pkgs/filesystem_utils/filesystem_session.py,sha256=BQ2Go8Mu9-GcnaWh2Pm4x7ugLVsre
41
42
  pkgs/serialization/__init__.py,sha256=LifasRW0a50A3qRFmo2bf3FQ6TXhZWOTz2-CVTgPjcQ,753
42
43
  pkgs/serialization/missing_sentry.py,sha256=aM_9KxbCk9dVvXvcOKgkIQBqFWvLhv8QlIUCiuFEXMo,806
43
44
  pkgs/serialization/opaque_key.py,sha256=FIfXEE0DA1U8R_taFbQ1RCoTSgehrPjP06-qvo-GeNQ,177
44
- pkgs/serialization/serial_class.py,sha256=xURwC05-ImnHU1pKM8BBYpzbrhTtiZr30UlzaA0T7zY,6110
45
+ pkgs/serialization/serial_class.py,sha256=anGUNEArLXjiEX3GoMNk7tn15LQWANXjxNrb5DqNK18,6252
45
46
  pkgs/serialization/serial_union.py,sha256=xpdeqCrRd0sNCaUwBQRzje6V40ndCbJpZrLX2K0d5xo,2741
46
47
  pkgs/serialization/yaml.py,sha256=yoJtu7_ixnJV6uTxA_U1PpK5F_ixT08AKVh5ocyYwXM,1466
47
48
  pkgs/serialization_util/__init__.py,sha256=MVKqHTUl2YnWZAFG9xCxu1SgmkQ5xPofrAGlYg6h7rI,330
@@ -67,7 +68,7 @@ pkgs/type_spec/util.py,sha256=79SLJsSPVnBe2_3CTF6J-7-QD9nRr6o8MKvfjyx53eI,4864
67
68
  pkgs/type_spec/actions_registry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
69
  pkgs/type_spec/actions_registry/__main__.py,sha256=JGwKxcAmrQdbpVR2vwknoimN1Q-r5h4SADw1cYLYzgk,4331
69
70
  pkgs/type_spec/actions_registry/emit_typescript.py,sha256=Z1ZM4zOw26tvLspvW6Emg79-jxjhNBse-8yaionbmeo,6066
70
- pkgs/type_spec/parts/base.py.prepart,sha256=wGNoDyQnLolHRZGRwHQX5TrPfKnu558NXCocYvqyroc,2174
71
+ pkgs/type_spec/parts/base.py.prepart,sha256=St6P21VP8Um_nagZFuSyNzYiKDSrsK3TNOuGY_1O8cg,2186
71
72
  pkgs/type_spec/parts/base.ts.prepart,sha256=2FJJvpg2olCcavxj0nbYWdwKl6KeScour2JjSvN42l8,1001
72
73
  pkgs/type_spec/type_info/__main__.py,sha256=pmVjVqXyVh8vKTNCTFgz80Sg74C5BKToP3E6GS-X_So,857
73
74
  pkgs/type_spec/type_info/emit_type_info.py,sha256=EzX0ONjrLtQFlN5cEAaw2RPVyadmgmZazOfqHUbL_PI,13362
@@ -98,14 +99,14 @@ uncountable/integration/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
98
99
  uncountable/integration/db/connect.py,sha256=mE3bdV0huclH2iT_dXCQdRL4LkjIuf_myAR64RTWXEs,498
99
100
  uncountable/integration/db/session.py,sha256=96cGQXpe6IugBTdSsjdP0S5yhJ6toSmbVB6qhc3FJzE,693
100
101
  uncountable/integration/executors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
101
- uncountable/integration/executors/executors.py,sha256=CbwatKkHrLhnqYr_nsBjr0KYeOn8KqijxrZPHbxChBY,1961
102
+ uncountable/integration/executors/executors.py,sha256=2OXFUJiG6hlkIB2NUZldobiBk9xSWuk7evvr5wlesG4,5119
102
103
  uncountable/integration/executors/generic_upload_executor.py,sha256=0vs9NVk1UL2FBhiMCH6o8p4KtVXNFNvv861QCOD3UU4,10375
103
104
  uncountable/integration/executors/script_executor.py,sha256=BBQ9f0l7uH2hgKf60jtm-pONzwk-EeOhM2qBAbv_URo,846
104
105
  uncountable/integration/queue_runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
- uncountable/integration/queue_runner/job_scheduler.py,sha256=5Z74Wb17oohz7EFN40JBymH1UWW7-Dnk9HhOz3wZ08E,5005
106
+ uncountable/integration/queue_runner/job_scheduler.py,sha256=lhvcl11jyk_wg9BSc1Xyh5u8iEtsdqQFW83FPLupjQI,6189
106
107
  uncountable/integration/queue_runner/queue_runner.py,sha256=0BmYu5zHdothTevGsB-nXg6MBd1UD-WkP3h1WCKMdQg,710
107
108
  uncountable/integration/queue_runner/types.py,sha256=8qTq29BTSa5rmW6CBlBntP0pNIiDcwu1wHa78pjroS0,219
108
- uncountable/integration/queue_runner/worker.py,sha256=pYLd6D3-ZSM3zcd7UKwyYUADVYEAUK9Hfi0PprwkNqo,4170
109
+ uncountable/integration/queue_runner/worker.py,sha256=EMDtdObowaq0aHndH1bBmlSIOih0jF3Gcn7Yl6NNeOM,4265
109
110
  uncountable/integration/queue_runner/command_server/__init__.py,sha256=gQPVILGpWzCr2i5GJyoqna7AOSFvtn4tav69gB78mTQ,571
110
111
  uncountable/integration/queue_runner/command_server/command_client.py,sha256=DJb0TUVFkiiLBEQzHSN94sTRnuEbutNEgdN39XmnOXI,2046
111
112
  uncountable/integration/queue_runner/command_server/command_server.py,sha256=yyXryhiEC2eGS0yFElLGsVzSKwOuYvj-zp22jQorkv0,2138
@@ -131,7 +132,7 @@ uncountable/types/async_jobs_t.py,sha256=sEh1Ev46ff4n1v8mMV3rEbH3MGmaXnLuvYf0UhD
131
132
  uncountable/types/auth_retrieval.py,sha256=FY8Vr_BWD4O8PsauPNt_7_08YZSHFaUlTT72L5XJ-4o,570
132
133
  uncountable/types/auth_retrieval_t.py,sha256=D2ptCIsuCecJa_P8K2qrNk2-zz1WuBpOrsZ65BRP-Dw,2221
133
134
  uncountable/types/base.py,sha256=xVSjWvA_fUUnkCg83EjoYEFvAfmskinKFMeYFOxNc9E,359
134
- uncountable/types/base_t.py,sha256=XXjZXexx0xWFUxMMhW8i9nIL6n8dsZVsHwdgnhZ0zJ4,2714
135
+ uncountable/types/base_t.py,sha256=ThxlCKyUBEj7sCRmfvWm2w4b6IDVvUkbAIISNxWTFxE,2726
135
136
  uncountable/types/calculations.py,sha256=FFO_D3BbKoGDZnqWvTKpW4KF359i2vrKjpdFCLYzJC0,284
136
137
  uncountable/types/calculations_t.py,sha256=157qD0VqijD5kNDF5BRsfGli3WaPGnNjoo2o2CPX-Ik,669
137
138
  uncountable/types/chemical_structure.py,sha256=E-LnikTFDoVQ1b2zKaVUIO_PAKm-7aZZYJi8I8SDSic,302
@@ -142,7 +143,7 @@ uncountable/types/client_config_t.py,sha256=6dStfR0IEHiPW8f9_aF3DD_tHmXXw2rEVrgp
142
143
  uncountable/types/curves.py,sha256=W6uMpG5SyW1MS82szNpxkFEn1MnxNpBFyFbQb2Ysfng,366
143
144
  uncountable/types/curves_t.py,sha256=lKhRM-2cZ_sFaW7pa_I_Ipz_pJhm3_yTFehRXI79pKk,1416
144
145
  uncountable/types/entity.py,sha256=ECvhswTj9xp4gUEKTZoZYyxHvx1oyvE5FNiGNfSyUgk,528
145
- uncountable/types/entity_t.py,sha256=78elxgVHHQ9GM9uvQVtTMSLnRXgDiznk9GEbAIzlK-k,16246
146
+ uncountable/types/entity_t.py,sha256=_a7maOh51nJPigkfdDipJ0XB9h8G4N6-VAWIQHNbh3o,16491
146
147
  uncountable/types/experiment_groups.py,sha256=_0OXcPzSAbkE-rfKt5tPx178YJ4pcEKZvrCxUHgDnvw,309
147
148
  uncountable/types/experiment_groups_t.py,sha256=qEs8YW0eJOJ_sCOObT5v9QRx9wsjLYpJqJhCJXa-vNA,721
148
149
  uncountable/types/field_values.py,sha256=uuIWX-xmfvcinYPdfkWJeb56zzQY01mc9rmotMPMh24,503
@@ -162,7 +163,7 @@ uncountable/types/inputs_t.py,sha256=CpuuKRduZGET_wvkGUpUFN6rbZCHsdOIp1veEM-hspI
162
163
  uncountable/types/integration_server.py,sha256=61NuGs1pbgovU5Vuje7oN9HpLwOGCCw9Q_CcUvt_0qI,385
163
164
  uncountable/types/integration_server_t.py,sha256=wa45RWChRsj2oAvWcOfZXA2xZxyEEkzltuJqZwKTna8,1048
164
165
  uncountable/types/job_definition.py,sha256=DEma_s-0oBo2tPI5u9IU_UDw-9MWbn4mTZsd_RHiYGE,1667
165
- uncountable/types/job_definition_t.py,sha256=N9080NAzwfYQKTusY2vs3z1UrM5s_QGtzWyoFxr2_iM,7931
166
+ uncountable/types/job_definition_t.py,sha256=whsat5825Jou1-67dbOkqiibpoavGcsaOhJ3APTUh2Q,7948
166
167
  uncountable/types/outputs.py,sha256=sUZx_X-TKCZtLm1YCEH8OISX9DdPlv9ZuUfM3-askCc,281
167
168
  uncountable/types/outputs_t.py,sha256=AdJZvIzqikHV9CnlC24WEo0OUe-5vrD4cjMqc2txEs0,765
168
169
  uncountable/types/overrides.py,sha256=Mv-smwK1B3pvbt48fNOiqkeQn9wMgYlBFJKUBOJqceE,431
@@ -285,7 +286,7 @@ uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr
285
286
  uncountable/types/api/triggers/run_trigger.py,sha256=-oZgPyn43xEKSCs81DVNzwaYMCdRJxbM9GY6fsqKwf4,1090
286
287
  uncountable/types/api/uploader/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
287
288
  uncountable/types/api/uploader/invoke_uploader.py,sha256=6mwVG136oLp9JcbB2I-kZnrcm3aeZzYZB-SFjEImY2o,1314
288
- UncountablePythonSDK-0.0.79.dist-info/METADATA,sha256=iq6fGPYZf2nEIM20TliAWLslL5xwXV9D9c6Y4jROeKA,2051
289
- UncountablePythonSDK-0.0.79.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
290
- UncountablePythonSDK-0.0.79.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
291
- UncountablePythonSDK-0.0.79.dist-info/RECORD,,
289
+ UncountablePythonSDK-0.0.81.dist-info/METADATA,sha256=hfFny-tLIUG0nrKcCY0eAxGDFgo-Q7wUXyqSczrBKpU,2051
290
+ UncountablePythonSDK-0.0.81.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
291
+ UncountablePythonSDK-0.0.81.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
292
+ UncountablePythonSDK-0.0.81.dist-info/RECORD,,
@@ -0,0 +1,15 @@
1
+ import typing
2
+
3
+ from uncountable.integration.job import JobArguments, WebhookJob, register_job
4
+ from uncountable.types.job_definition_t import JobResult
5
+
6
+
7
+ @register_job
8
+ class WebhookExample(WebhookJob):
9
+ @property
10
+ def payload_type(self) -> typing.Any:
11
+ return super().payload_type
12
+
13
+ def run(self, args: JobArguments, payload: typing.Any) -> JobResult:
14
+ args.logger.log_info(f"webhook invoked with payload: {payload}")
15
+ return JobResult(success=True)
@@ -13,7 +13,31 @@ jobs:
13
13
  type: cron
14
14
  name: MyCron - Example
15
15
  cron_spec: "* * * * *"
16
- executor:
16
+ executor:
17
17
  type: script
18
18
  import_path: example_cron
19
+ logging_settings:
20
+ enabled: true
21
+ share_with_user_groups:
22
+ - admin:
23
+ type: ref_name
24
+ ref_name: admin
19
25
 
26
+ - id: example_wh1
27
+ type: webhook
28
+ name: Webhook 1
29
+ signature_key_secret:
30
+ type: env
31
+ env_key: WH1_SIGNATURE_KEY
32
+ executor:
33
+ type: script
34
+ import_path: example_wh
35
+ - id: example_wh2
36
+ type: webhook
37
+ name: Webhook 2
38
+ signature_key_secret:
39
+ type: env
40
+ env_key: WH2_SIGNATURE_KEY
41
+ executor:
42
+ type: script
43
+ import_path: example_wh
@@ -96,6 +96,10 @@ class SerialClassDataInspector:
96
96
  def named_type_path(self) -> Optional[str]:
97
97
  return self.current.named_type_path
98
98
 
99
+ @property
100
+ def is_field_proper(self) -> bool:
101
+ return self.current.from_decorator and self.current.named_type_path is not None
102
+
99
103
 
100
104
  def _get_merged_serial_class_data(type_class: type[Any]) -> _SerialClassData | None:
101
105
  base_class_data = (
@@ -22,8 +22,8 @@ PureJsonScalar = Union[str, float, bool, None]
22
22
  # Regular expressions for identifying ref names and IDs. Ref names should be
23
23
  # using this regular expression as a constriant in the database.
24
24
  REF_NAME_REGEX = r"^[a-zA-Z0-9_/-]+$"
25
- # Does not support nonpositive integers at the moment.
26
- ID_REGEX = r"[1-9][0-9]{0,20}"
25
+ # Ids matching a strict integer number are converted to integers
26
+ ID_REGEX = r"-?[1-9][0-9]{0,20}"
27
27
 
28
28
 
29
29
  if TYPE_CHECKING:
@@ -1,9 +1,17 @@
1
1
  from typing import assert_never
2
2
 
3
+ from uncountable.core.client import Client
3
4
  from uncountable.integration.executors.generic_upload_executor import GenericUploadJob
4
5
  from uncountable.integration.executors.script_executor import resolve_script_executor
5
6
  from uncountable.integration.job import Job, JobArguments
6
- from uncountable.types import job_definition_t
7
+ from uncountable.types import (
8
+ async_jobs_t,
9
+ entity_t,
10
+ field_values_t,
11
+ identifier_t,
12
+ job_definition_t,
13
+ transition_entity_phase_t,
14
+ )
7
15
 
8
16
 
9
17
  def resolve_executor(
@@ -24,6 +32,49 @@ def resolve_executor(
24
32
  assert_never(job_executor)
25
33
 
26
34
 
35
+ def _create_run_entity(
36
+ *, client: Client, logging_settings: job_definition_t.JobLoggingSettings
37
+ ) -> entity_t.Entity:
38
+ run_entity = client.create_entity(
39
+ entity_type=entity_t.EntityType.ASYNC_JOB,
40
+ definition_key=identifier_t.IdentifierKeyRefName(
41
+ ref_name="unc_integration_server_run_definition"
42
+ ),
43
+ field_values=[
44
+ field_values_t.FieldRefNameValue(
45
+ field_ref_name=async_jobs_t.ASYNC_JOB_TYPE_FIELD_REF_NAME,
46
+ value=async_jobs_t.AsyncJobType.INTEGRATION_SERVER_RUN,
47
+ ),
48
+ field_values_t.FieldRefNameValue(
49
+ field_ref_name=async_jobs_t.ASYNC_JOB_STATUS_FIELD_REF_NAME,
50
+ value=async_jobs_t.AsyncJobStatus.IN_PROGRESS,
51
+ ),
52
+ ],
53
+ ).entity
54
+ client.transition_entity_phase(
55
+ entity=run_entity,
56
+ transition=transition_entity_phase_t.TransitionIdentifierPhases(
57
+ phase_from_key=identifier_t.IdentifierKeyRefName(
58
+ ref_name="unc_integration_server_run__queued"
59
+ ),
60
+ phase_to_key=identifier_t.IdentifierKeyRefName(
61
+ ref_name="unc_integration_server_run__started"
62
+ ),
63
+ ),
64
+ )
65
+ if logging_settings.share_with_user_groups is not None:
66
+ client.grant_entity_permissions(
67
+ entity_type=entity_t.EntityType.ASYNC_JOB,
68
+ entity_key=identifier_t.IdentifierKeyId(id=run_entity.id),
69
+ permission_types=[
70
+ entity_t.EntityPermissionType.READ,
71
+ entity_t.EntityPermissionType.WRITE,
72
+ ],
73
+ user_group_keys=logging_settings.share_with_user_groups,
74
+ )
75
+ return run_entity
76
+
77
+
27
78
  def execute_job(
28
79
  *,
29
80
  job_definition: job_definition_t.JobDefinition,
@@ -35,10 +86,28 @@ def execute_job(
35
86
 
36
87
  job_logger.log_info("running job")
37
88
 
89
+ run_entity: entity_t.Entity | None = None
38
90
  try:
91
+ if (
92
+ job_definition.logging_settings is not None
93
+ and job_definition.logging_settings.enabled
94
+ ):
95
+ run_entity = _create_run_entity(
96
+ client=args.client, logging_settings=job_definition.logging_settings
97
+ )
39
98
  result = job.run_outer(args=args)
40
99
  except Exception as e:
41
100
  job_logger.log_exception(e)
101
+ if run_entity is not None:
102
+ args.client.set_values(
103
+ entity=run_entity,
104
+ values=[
105
+ field_values_t.ArgumentValueRefName(
106
+ field_ref_name=async_jobs_t.ASYNC_JOB_STATUS_FIELD_REF_NAME,
107
+ value=async_jobs_t.AsyncJobStatus.ERROR,
108
+ ),
109
+ ],
110
+ )
42
111
  return job_definition_t.JobResult(success=False)
43
112
 
44
113
  if args.batch_processor.current_queue_size() != 0:
@@ -52,5 +121,17 @@ def execute_job(
52
121
  "success": result.success,
53
122
  },
54
123
  )
124
+ if run_entity is not None:
125
+ args.client.set_values(
126
+ entity=run_entity,
127
+ values=[
128
+ field_values_t.ArgumentValueRefName(
129
+ field_ref_name=async_jobs_t.ASYNC_JOB_STATUS_FIELD_REF_NAME,
130
+ value=async_jobs_t.AsyncJobStatus.COMPLETED
131
+ if result.success
132
+ else async_jobs_t.AsyncJobStatus.ERROR,
133
+ ),
134
+ ],
135
+ )
55
136
 
56
137
  return result
@@ -8,6 +8,7 @@ from opentelemetry.trace import get_current_span
8
8
  from uncountable.integration.db.connect import IntegrationDBService, create_db_engine
9
9
  from uncountable.integration.db.session import get_session_maker
10
10
  from uncountable.integration.queue_runner.command_server import (
11
+ CommandEnqueueJob,
11
12
  CommandEnqueueJobResponse,
12
13
  CommandQueue,
13
14
  CommandTask,
@@ -99,6 +100,41 @@ async def start_scheduler(command_queue: CommandQueue) -> None:
99
100
  return
100
101
  await worker.listen_queue.put(queued_job)
101
102
 
103
+ async def _enqueue_or_deduplicate_job(
104
+ job_ref_name: str,
105
+ payload: queued_job_t.QueuedJobPayload,
106
+ ) -> str:
107
+ if isinstance(
108
+ payload.invocation_context,
109
+ queued_job_t.InvocationContextCron,
110
+ ):
111
+ existing_queued_jobs = datastore.load_job_queue()
112
+ duplicate_job = next(
113
+ (
114
+ job
115
+ for job in existing_queued_jobs
116
+ if job.job_ref_name == job_ref_name
117
+ ),
118
+ None,
119
+ )
120
+ if duplicate_job is not None:
121
+ return duplicate_job.queued_job_uuid
122
+ queued_job = datastore.add_job_to_queue(
123
+ job_payload=payload,
124
+ job_ref_name=job_ref_name,
125
+ )
126
+ await enqueue_queued_job(queued_job)
127
+ return queued_job.queued_job_uuid
128
+
129
+ async def _handle_enqueue_job_command(command: CommandEnqueueJob) -> None:
130
+ queued_job_uuid = await _enqueue_or_deduplicate_job(
131
+ job_ref_name=command.job_ref_name,
132
+ payload=command.payload,
133
+ )
134
+ await command.response_queue.put(
135
+ CommandEnqueueJobResponse(queued_job_uuid=queued_job_uuid)
136
+ )
137
+
102
138
  for queued_job in queued_jobs:
103
139
  await enqueue_queued_job(queued_job)
104
140
 
@@ -112,15 +148,11 @@ async def start_scheduler(command_queue: CommandQueue) -> None:
112
148
  for task in finished:
113
149
  if task == command_task:
114
150
  command = command_task.result()
115
- queued_job = datastore.add_job_to_queue(
116
- job_payload=command.payload, job_ref_name=command.job_ref_name
117
- )
118
- await command.response_queue.put(
119
- CommandEnqueueJobResponse(
120
- queued_job_uuid=queued_job.queued_job_uuid
121
- )
122
- )
123
- await enqueue_queued_job(queued_job)
151
+ match command:
152
+ case CommandEnqueueJob():
153
+ await _handle_enqueue_job_command(command=command)
154
+ case _:
155
+ typing.assert_never(command)
124
156
  command_task = asyncio.create_task(command_queue.get())
125
157
  elif task == result_task:
126
158
  queued_job_result = result_task.result()
@@ -106,3 +106,6 @@ def run_queued_job(
106
106
  except Exception as e:
107
107
  job_logger.log_exception(e)
108
108
  return job_definition_t.JobResult(success=False)
109
+ except BaseException as e:
110
+ job_logger.log_exception(e)
111
+ raise e
@@ -39,8 +39,8 @@ PureJsonScalar = Union[str, float, bool, None]
39
39
  # Regular expressions for identifying ref names and IDs. Ref names should be
40
40
  # using this regular expression as a constriant in the database.
41
41
  REF_NAME_REGEX = r"^[a-zA-Z0-9_/-]+$"
42
- # Does not support nonpositive integers at the moment.
43
- ID_REGEX = r"[1-9][0-9]{0,20}"
42
+ # Ids matching a strict integer number are converted to integers
43
+ ID_REGEX = r"-?[1-9][0-9]{0,20}"
44
44
 
45
45
 
46
46
  if TYPE_CHECKING:
@@ -70,10 +70,12 @@ __all__: list[str] = [
70
70
  "ingredient": "Ingredient",
71
71
  "ingredient_attribute": "Ingredient Attribute",
72
72
  "ingredient_attribute_category": "Ingredient Attribute Category",
73
+ "ingredient_attribute_value": "Ingredient Attribute Value",
73
74
  "ingredient_category": "Ingredient Category (Project)",
74
75
  "ingredient_category_all": "Ingredient Category",
75
76
  "ingredient_category_all_material_family": "Ingredient Category Material Family",
76
77
  "ingredient_lot": "Ingredient Lot",
78
+ "ingredient_mat_family": "Ingredient Material Family",
77
79
  "ingredient_role": "Ingredient Role",
78
80
  "ingredient_tag": "Ingredient Subcategory",
79
81
  "ingredient_tag_map": "Ingredient Tag Map",
@@ -225,10 +227,12 @@ class EntityType(StrEnum):
225
227
  INGREDIENT = "ingredient"
226
228
  INGREDIENT_ATTRIBUTE = "ingredient_attribute"
227
229
  INGREDIENT_ATTRIBUTE_CATEGORY = "ingredient_attribute_category"
230
+ INGREDIENT_ATTRIBUTE_VALUE = "ingredient_attribute_value"
228
231
  INGREDIENT_CATEGORY = "ingredient_category"
229
232
  INGREDIENT_CATEGORY_ALL = "ingredient_category_all"
230
233
  INGREDIENT_CATEGORY_ALL_MATERIAL_FAMILY = "ingredient_category_all_material_family"
231
234
  INGREDIENT_LOT = "ingredient_lot"
235
+ INGREDIENT_MAT_FAMILY = "ingredient_mat_family"
232
236
  INGREDIENT_ROLE = "ingredient_role"
233
237
  INGREDIENT_TAG = "ingredient_tag"
234
238
  INGREDIENT_TAG_MAP = "ingredient_tag_map"
@@ -12,9 +12,9 @@ import dataclasses
12
12
  from pkgs.serialization import serial_class
13
13
  from pkgs.serialization import serial_union_annotation
14
14
  from . import auth_retrieval_t
15
- from . import base_t
16
15
  from . import client_config_t
17
16
  from . import generic_upload_t
17
+ from . import identifier_t
18
18
  from . import integration_server_t
19
19
  from . import secret_retrieval_t
20
20
 
@@ -172,7 +172,7 @@ JobExecutor = typing.Annotated[
172
172
  @dataclasses.dataclass(kw_only=True)
173
173
  class JobLoggingSettings:
174
174
  enabled: bool = False
175
- share_with_user_groups: typing.Optional[list[base_t.ObjectId]] = None
175
+ share_with_user_groups: typing.Optional[list[identifier_t.IdentifierKey]] = None
176
176
 
177
177
 
178
178
  # DO NOT MODIFY -- This file is generated by type_spec