UncountablePythonSDK 0.0.83__py3-none-any.whl → 0.0.132__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.
- docs/conf.py +54 -7
- docs/index.md +107 -4
- docs/integration_examples/create_ingredient.md +43 -0
- docs/integration_examples/create_output.md +56 -0
- docs/integration_examples/index.md +6 -0
- docs/justfile +2 -2
- docs/requirements.txt +6 -4
- examples/basic_auth.py +7 -0
- examples/create_ingredient_sdk.py +34 -0
- examples/download_files.py +26 -0
- examples/integration-server/jobs/materials_auto/concurrent_cron.py +11 -0
- examples/integration-server/jobs/materials_auto/example_cron.py +3 -0
- examples/integration-server/jobs/materials_auto/example_http.py +47 -0
- examples/integration-server/jobs/materials_auto/example_instrument.py +100 -0
- examples/integration-server/jobs/materials_auto/example_parse.py +140 -0
- examples/integration-server/jobs/materials_auto/example_predictions.py +61 -0
- examples/integration-server/jobs/materials_auto/example_runsheet_wh.py +39 -0
- examples/integration-server/jobs/materials_auto/example_wh.py +17 -9
- examples/integration-server/jobs/materials_auto/profile.yaml +61 -0
- examples/integration-server/pyproject.toml +10 -10
- examples/oauth.py +7 -0
- examples/set_recipe_metadata_file.py +1 -1
- examples/upload_files.py +1 -2
- pkgs/argument_parser/__init__.py +8 -0
- pkgs/argument_parser/_is_namedtuple.py +3 -0
- pkgs/argument_parser/argument_parser.py +196 -63
- pkgs/filesystem_utils/__init__.py +1 -0
- pkgs/filesystem_utils/_blob_session.py +144 -0
- pkgs/filesystem_utils/_gdrive_session.py +5 -5
- pkgs/filesystem_utils/_s3_session.py +2 -1
- pkgs/filesystem_utils/_sftp_session.py +6 -3
- pkgs/filesystem_utils/file_type_utils.py +30 -10
- pkgs/serialization/__init__.py +7 -2
- pkgs/serialization/annotation.py +64 -0
- pkgs/serialization/missing_sentry.py +1 -1
- pkgs/serialization/opaque_key.py +1 -1
- pkgs/serialization/serial_alias.py +47 -0
- pkgs/serialization/serial_class.py +40 -48
- pkgs/serialization/serial_generic.py +16 -0
- pkgs/serialization/serial_union.py +16 -16
- pkgs/serialization_util/__init__.py +6 -0
- pkgs/serialization_util/dataclasses.py +14 -0
- pkgs/serialization_util/serialization_helpers.py +15 -5
- pkgs/type_spec/actions_registry/__main__.py +0 -4
- pkgs/type_spec/actions_registry/emit_typescript.py +2 -4
- pkgs/type_spec/builder.py +248 -70
- pkgs/type_spec/builder_types.py +9 -0
- pkgs/type_spec/config.py +40 -7
- pkgs/type_spec/cross_output_links.py +99 -0
- pkgs/type_spec/emit_open_api.py +121 -34
- pkgs/type_spec/emit_open_api_util.py +5 -5
- pkgs/type_spec/emit_python.py +277 -86
- pkgs/type_spec/emit_typescript.py +102 -29
- pkgs/type_spec/emit_typescript_util.py +66 -10
- pkgs/type_spec/load_types.py +16 -3
- pkgs/type_spec/non_discriminated_union_exceptions.py +14 -0
- pkgs/type_spec/open_api_util.py +29 -4
- pkgs/type_spec/parts/base.py.prepart +11 -8
- pkgs/type_spec/parts/base.ts.prepart +4 -0
- pkgs/type_spec/type_info/__main__.py +3 -1
- pkgs/type_spec/type_info/emit_type_info.py +115 -22
- pkgs/type_spec/ui_entry_actions/__init__.py +4 -0
- pkgs/type_spec/ui_entry_actions/generate_ui_entry_actions.py +308 -0
- pkgs/type_spec/util.py +3 -3
- pkgs/type_spec/value_spec/__main__.py +26 -9
- pkgs/type_spec/value_spec/convert_type.py +18 -0
- pkgs/type_spec/value_spec/emit_python.py +13 -3
- pkgs/type_spec/value_spec/types.py +1 -1
- uncountable/core/async_batch.py +1 -1
- uncountable/core/client.py +133 -34
- uncountable/core/environment.py +3 -3
- uncountable/core/file_upload.py +39 -15
- uncountable/integration/cli.py +116 -23
- uncountable/integration/construct_client.py +3 -3
- uncountable/integration/executors/executors.py +12 -2
- uncountable/integration/executors/generic_upload_executor.py +66 -14
- uncountable/integration/http_server/__init__.py +5 -0
- uncountable/integration/http_server/types.py +69 -0
- uncountable/integration/job.py +192 -7
- uncountable/integration/queue_runner/command_server/__init__.py +4 -0
- uncountable/integration/queue_runner/command_server/command_client.py +65 -0
- uncountable/integration/queue_runner/command_server/command_server.py +83 -5
- uncountable/integration/queue_runner/command_server/constants.py +4 -0
- uncountable/integration/queue_runner/command_server/protocol/command_server.proto +36 -0
- uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.py +28 -11
- uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.pyi +77 -1
- uncountable/integration/queue_runner/command_server/protocol/command_server_pb2_grpc.py +135 -0
- uncountable/integration/queue_runner/command_server/types.py +25 -2
- uncountable/integration/queue_runner/datastore/datastore_sqlite.py +168 -11
- uncountable/integration/queue_runner/datastore/interface.py +10 -0
- uncountable/integration/queue_runner/datastore/model.py +8 -1
- uncountable/integration/queue_runner/job_scheduler.py +63 -23
- uncountable/integration/queue_runner/queue_runner.py +10 -2
- uncountable/integration/queue_runner/worker.py +3 -5
- uncountable/integration/scan_profiles.py +1 -1
- uncountable/integration/scheduler.py +74 -25
- uncountable/integration/secret_retrieval/retrieve_secret.py +1 -1
- uncountable/integration/server.py +42 -12
- uncountable/integration/telemetry.py +63 -10
- uncountable/integration/webhook_server/entrypoint.py +39 -112
- uncountable/types/__init__.py +58 -1
- uncountable/types/api/batch/execute_batch.py +5 -6
- uncountable/types/api/batch/execute_batch_load_async.py +2 -3
- uncountable/types/api/chemical/convert_chemical_formats.py +10 -5
- uncountable/types/api/condition_parameters/__init__.py +1 -0
- uncountable/types/api/condition_parameters/upsert_condition_match.py +72 -0
- uncountable/types/api/entity/create_entities.py +7 -7
- uncountable/types/api/entity/create_entity.py +8 -8
- uncountable/types/api/entity/create_or_update_entity.py +48 -0
- uncountable/types/api/entity/export_entities.py +59 -0
- uncountable/types/api/entity/get_entities_data.py +3 -4
- uncountable/types/api/entity/grant_entity_permissions.py +6 -6
- uncountable/types/api/entity/list_aggregate.py +79 -0
- uncountable/types/api/entity/list_entities.py +34 -10
- uncountable/types/api/entity/lock_entity.py +4 -4
- uncountable/types/api/entity/lookup_entity.py +116 -0
- uncountable/types/api/entity/resolve_entity_ids.py +5 -6
- uncountable/types/api/entity/set_entity_field_values.py +44 -0
- uncountable/types/api/entity/set_values.py +3 -3
- uncountable/types/api/entity/transition_entity_phase.py +14 -7
- uncountable/types/api/entity/unlock_entity.py +3 -3
- uncountable/types/api/equipment/associate_equipment_input.py +2 -3
- uncountable/types/api/field_options/upsert_field_options.py +7 -7
- uncountable/types/api/files/__init__.py +1 -0
- uncountable/types/api/files/download_file.py +77 -0
- uncountable/types/api/id_source/list_id_source.py +6 -7
- uncountable/types/api/id_source/match_id_source.py +4 -5
- uncountable/types/api/input_groups/get_input_group_names.py +3 -4
- uncountable/types/api/inputs/create_inputs.py +10 -9
- uncountable/types/api/inputs/get_input_data.py +11 -12
- uncountable/types/api/inputs/get_input_names.py +6 -7
- uncountable/types/api/inputs/get_inputs_data.py +6 -7
- uncountable/types/api/inputs/set_input_attribute_values.py +5 -6
- uncountable/types/api/inputs/set_input_category.py +5 -5
- uncountable/types/api/inputs/set_input_subcategories.py +3 -3
- uncountable/types/api/inputs/set_intermediate_type.py +4 -4
- uncountable/types/api/integrations/__init__.py +1 -0
- uncountable/types/api/integrations/publish_realtime_data.py +41 -0
- uncountable/types/api/integrations/push_notification.py +49 -0
- uncountable/types/api/integrations/register_sockets_token.py +41 -0
- uncountable/types/api/listing/__init__.py +1 -0
- uncountable/types/api/listing/fetch_listing.py +58 -0
- uncountable/types/api/material_families/update_entity_material_families.py +3 -4
- uncountable/types/api/notebooks/__init__.py +1 -0
- uncountable/types/api/notebooks/add_notebook_content.py +119 -0
- uncountable/types/api/outputs/get_output_data.py +12 -13
- uncountable/types/api/outputs/get_output_names.py +5 -6
- uncountable/types/api/outputs/get_output_organization.py +173 -0
- uncountable/types/api/outputs/resolve_output_conditions.py +7 -8
- uncountable/types/api/permissions/set_core_permissions.py +16 -10
- uncountable/types/api/project/get_projects.py +6 -7
- uncountable/types/api/project/get_projects_data.py +7 -8
- uncountable/types/api/recipe_links/create_recipe_link.py +5 -5
- uncountable/types/api/recipe_links/remove_recipe_link.py +4 -4
- uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +6 -7
- uncountable/types/api/recipes/add_recipe_to_project.py +3 -3
- uncountable/types/api/recipes/add_time_series_data.py +64 -0
- uncountable/types/api/recipes/archive_recipes.py +4 -4
- uncountable/types/api/recipes/associate_recipe_as_input.py +5 -5
- uncountable/types/api/recipes/associate_recipe_as_lot.py +3 -3
- uncountable/types/api/recipes/clear_recipe_outputs.py +3 -3
- uncountable/types/api/recipes/create_mix_order.py +44 -0
- uncountable/types/api/recipes/create_recipe.py +8 -9
- uncountable/types/api/recipes/create_recipes.py +8 -9
- uncountable/types/api/recipes/disassociate_recipe_as_input.py +3 -3
- uncountable/types/api/recipes/edit_recipe_inputs.py +101 -24
- uncountable/types/api/recipes/get_column_calculation_values.py +4 -5
- uncountable/types/api/recipes/get_curve.py +4 -5
- uncountable/types/api/recipes/get_recipe_calculations.py +6 -7
- uncountable/types/api/recipes/get_recipe_links.py +3 -4
- uncountable/types/api/recipes/get_recipe_names.py +3 -4
- uncountable/types/api/recipes/get_recipe_output_metadata.py +5 -6
- uncountable/types/api/recipes/get_recipes_data.py +62 -34
- uncountable/types/api/recipes/lock_recipes.py +9 -8
- uncountable/types/api/recipes/remove_recipe_from_project.py +3 -3
- uncountable/types/api/recipes/set_recipe_inputs.py +9 -10
- uncountable/types/api/recipes/set_recipe_metadata.py +3 -3
- uncountable/types/api/recipes/set_recipe_output_annotations.py +11 -12
- uncountable/types/api/recipes/set_recipe_output_file.py +5 -6
- uncountable/types/api/recipes/set_recipe_outputs.py +24 -13
- uncountable/types/api/recipes/set_recipe_tags.py +14 -9
- uncountable/types/api/recipes/set_recipe_total.py +59 -0
- uncountable/types/api/recipes/unarchive_recipes.py +3 -3
- uncountable/types/api/recipes/unlock_recipes.py +7 -6
- uncountable/types/api/runsheet/__init__.py +1 -0
- uncountable/types/api/runsheet/complete_async_upload.py +41 -0
- uncountable/types/api/triggers/run_trigger.py +4 -4
- uncountable/types/api/uploader/complete_async_parse.py +46 -0
- uncountable/types/api/uploader/invoke_uploader.py +4 -5
- uncountable/types/api/user/__init__.py +1 -0
- uncountable/types/api/user/get_current_user_info.py +40 -0
- uncountable/types/async_batch.py +1 -1
- uncountable/types/async_batch_processor.py +506 -23
- uncountable/types/async_batch_t.py +35 -8
- uncountable/types/async_jobs.py +0 -1
- uncountable/types/async_jobs_t.py +1 -2
- uncountable/types/auth_retrieval.py +0 -1
- uncountable/types/auth_retrieval_t.py +6 -6
- uncountable/types/base.py +0 -1
- uncountable/types/base_t.py +11 -9
- uncountable/types/calculations.py +0 -1
- uncountable/types/calculations_t.py +1 -2
- uncountable/types/chemical_structure.py +0 -1
- uncountable/types/chemical_structure_t.py +5 -5
- uncountable/types/client_base.py +614 -69
- uncountable/types/client_config.py +1 -1
- uncountable/types/client_config_t.py +13 -3
- uncountable/types/curves.py +0 -1
- uncountable/types/curves_t.py +6 -7
- uncountable/types/data.py +12 -0
- uncountable/types/data_t.py +103 -0
- uncountable/types/entity.py +1 -1
- uncountable/types/entity_t.py +90 -10
- uncountable/types/experiment_groups.py +0 -1
- uncountable/types/experiment_groups_t.py +1 -2
- uncountable/types/exports.py +8 -0
- uncountable/types/exports_t.py +34 -0
- uncountable/types/field_values.py +19 -1
- uncountable/types/field_values_t.py +242 -9
- uncountable/types/fields.py +0 -1
- uncountable/types/fields_t.py +1 -2
- uncountable/types/generic_upload.py +0 -1
- uncountable/types/generic_upload_t.py +14 -14
- uncountable/types/id_source.py +0 -1
- uncountable/types/id_source_t.py +13 -7
- uncountable/types/identifier.py +0 -1
- uncountable/types/identifier_t.py +10 -5
- uncountable/types/input_attributes.py +0 -1
- uncountable/types/input_attributes_t.py +3 -4
- uncountable/types/inputs.py +0 -1
- uncountable/types/inputs_t.py +3 -4
- uncountable/types/integration_server.py +0 -1
- uncountable/types/integration_server_t.py +13 -4
- uncountable/types/integration_session.py +10 -0
- uncountable/types/integration_session_t.py +60 -0
- uncountable/types/integrations.py +10 -0
- uncountable/types/integrations_t.py +62 -0
- uncountable/types/job_definition.py +2 -1
- uncountable/types/job_definition_t.py +57 -32
- uncountable/types/listing.py +9 -0
- uncountable/types/listing_t.py +51 -0
- uncountable/types/notices.py +8 -0
- uncountable/types/notices_t.py +37 -0
- uncountable/types/notifications.py +11 -0
- uncountable/types/notifications_t.py +74 -0
- uncountable/types/outputs.py +0 -1
- uncountable/types/outputs_t.py +2 -3
- uncountable/types/overrides.py +0 -1
- uncountable/types/overrides_t.py +10 -4
- uncountable/types/permissions.py +0 -1
- uncountable/types/permissions_t.py +1 -2
- uncountable/types/phases.py +0 -1
- uncountable/types/phases_t.py +1 -2
- uncountable/types/post_base.py +0 -1
- uncountable/types/post_base_t.py +1 -2
- uncountable/types/queued_job.py +2 -1
- uncountable/types/queued_job_t.py +29 -12
- uncountable/types/recipe_identifiers.py +0 -1
- uncountable/types/recipe_identifiers_t.py +18 -8
- uncountable/types/recipe_inputs.py +0 -1
- uncountable/types/recipe_inputs_t.py +1 -2
- uncountable/types/recipe_links.py +0 -1
- uncountable/types/recipe_links_t.py +3 -4
- uncountable/types/recipe_metadata.py +0 -1
- uncountable/types/recipe_metadata_t.py +9 -10
- uncountable/types/recipe_output_metadata.py +0 -1
- uncountable/types/recipe_output_metadata_t.py +1 -2
- uncountable/types/recipe_tags.py +0 -1
- uncountable/types/recipe_tags_t.py +1 -2
- uncountable/types/recipe_workflow_steps.py +0 -1
- uncountable/types/recipe_workflow_steps_t.py +7 -7
- uncountable/types/recipes.py +0 -1
- uncountable/types/recipes_t.py +2 -2
- uncountable/types/response.py +0 -1
- uncountable/types/response_t.py +2 -2
- uncountable/types/secret_retrieval.py +0 -1
- uncountable/types/secret_retrieval_t.py +7 -7
- uncountable/types/sockets.py +20 -0
- uncountable/types/sockets_t.py +169 -0
- uncountable/types/structured_filters.py +25 -0
- uncountable/types/structured_filters_t.py +248 -0
- uncountable/types/units.py +0 -1
- uncountable/types/units_t.py +1 -2
- uncountable/types/uploader.py +24 -0
- uncountable/types/uploader_t.py +222 -0
- uncountable/types/users.py +0 -1
- uncountable/types/users_t.py +1 -2
- uncountable/types/webhook_job.py +1 -1
- uncountable/types/webhook_job_t.py +14 -3
- uncountable/types/workflows.py +0 -1
- uncountable/types/workflows_t.py +3 -4
- uncountablepythonsdk-0.0.132.dist-info/METADATA +64 -0
- uncountablepythonsdk-0.0.132.dist-info/RECORD +363 -0
- {UncountablePythonSDK-0.0.83.dist-info → uncountablepythonsdk-0.0.132.dist-info}/WHEEL +1 -1
- UncountablePythonSDK-0.0.83.dist-info/METADATA +0 -60
- UncountablePythonSDK-0.0.83.dist-info/RECORD +0 -292
- docs/quickstart.md +0 -19
- {UncountablePythonSDK-0.0.83.dist-info → uncountablepythonsdk-0.0.132.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import signal
|
|
2
2
|
from dataclasses import asdict
|
|
3
3
|
from types import TracebackType
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import assert_never
|
|
5
5
|
|
|
6
6
|
from apscheduler.executors.pool import ThreadPoolExecutor
|
|
7
7
|
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
|
|
@@ -11,16 +11,28 @@ from apscheduler.triggers.cron import CronTrigger
|
|
|
11
11
|
from opentelemetry.trace import get_current_span
|
|
12
12
|
from sqlalchemy.engine.base import Engine
|
|
13
13
|
|
|
14
|
+
from uncountable.core.environment import get_local_admin_server_port
|
|
14
15
|
from uncountable.integration.cron import CronJobArgs, cron_job_executor
|
|
16
|
+
from uncountable.integration.queue_runner.command_server.command_client import (
|
|
17
|
+
send_vaccuum_queued_jobs_message,
|
|
18
|
+
)
|
|
15
19
|
from uncountable.integration.telemetry import Logger
|
|
16
20
|
from uncountable.types import base_t, job_definition_t
|
|
17
21
|
from uncountable.types.job_definition_t import (
|
|
18
22
|
CronJobDefinition,
|
|
19
|
-
|
|
23
|
+
HttpJobDefinitionBase,
|
|
20
24
|
)
|
|
21
25
|
|
|
22
26
|
_MAX_APSCHEDULER_CONCURRENT_JOBS = 1
|
|
23
27
|
|
|
28
|
+
VACCUUM_QUEUED_JOBS_JOB_ID = "vacuum_queued_jobs"
|
|
29
|
+
|
|
30
|
+
STATIC_JOB_IDS = {VACCUUM_QUEUED_JOBS_JOB_ID}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def vaccuum_queued_jobs() -> None:
|
|
34
|
+
send_vaccuum_queued_jobs_message(port=get_local_admin_server_port())
|
|
35
|
+
|
|
24
36
|
|
|
25
37
|
class IntegrationServer:
|
|
26
38
|
_scheduler: BaseScheduler
|
|
@@ -36,11 +48,27 @@ class IntegrationServer:
|
|
|
36
48
|
)
|
|
37
49
|
self._server_logger = Logger(get_current_span())
|
|
38
50
|
|
|
51
|
+
def _register_static_jobs(self) -> None:
|
|
52
|
+
all_job_ids = {job.id for job in self._scheduler.get_jobs()}
|
|
53
|
+
if VACCUUM_QUEUED_JOBS_JOB_ID in all_job_ids:
|
|
54
|
+
self._scheduler.remove_job(VACCUUM_QUEUED_JOBS_JOB_ID)
|
|
55
|
+
|
|
56
|
+
self._scheduler.add_job(
|
|
57
|
+
vaccuum_queued_jobs,
|
|
58
|
+
max_instances=1,
|
|
59
|
+
coalesce=True,
|
|
60
|
+
trigger=CronTrigger.from_crontab("5 4 * * 4"),
|
|
61
|
+
name="Vaccuum queued jobs",
|
|
62
|
+
id=VACCUUM_QUEUED_JOBS_JOB_ID,
|
|
63
|
+
kwargs={},
|
|
64
|
+
misfire_grace_time=None,
|
|
65
|
+
)
|
|
66
|
+
|
|
39
67
|
def register_jobs(self, profiles: list[job_definition_t.ProfileMetadata]) -> None:
|
|
40
|
-
valid_job_ids =
|
|
68
|
+
valid_job_ids: set[str] = set()
|
|
41
69
|
for profile_metadata in profiles:
|
|
42
70
|
for job_defn in profile_metadata.jobs:
|
|
43
|
-
valid_job_ids.
|
|
71
|
+
valid_job_ids.add(job_defn.id)
|
|
44
72
|
match job_defn:
|
|
45
73
|
case CronJobDefinition():
|
|
46
74
|
# Add to ap scheduler
|
|
@@ -86,14 +114,15 @@ class IntegrationServer:
|
|
|
86
114
|
misfire_grace_time=None,
|
|
87
115
|
**job_opts,
|
|
88
116
|
)
|
|
89
|
-
case
|
|
117
|
+
case HttpJobDefinitionBase():
|
|
90
118
|
pass
|
|
91
119
|
case _:
|
|
92
120
|
assert_never(job_defn)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
121
|
+
all_job_ids = {job.id for job in self._scheduler.get_jobs()}
|
|
122
|
+
invalid_job_ids = all_job_ids.difference(valid_job_ids.union(STATIC_JOB_IDS))
|
|
123
|
+
|
|
124
|
+
for job_id in invalid_job_ids:
|
|
125
|
+
self._scheduler.remove_job(job_id)
|
|
97
126
|
|
|
98
127
|
def serve_forever(self) -> None:
|
|
99
128
|
signal.pause()
|
|
@@ -106,12 +135,13 @@ class IntegrationServer:
|
|
|
106
135
|
|
|
107
136
|
def __enter__(self) -> "IntegrationServer":
|
|
108
137
|
self._start_apscheduler()
|
|
138
|
+
self._register_static_jobs()
|
|
109
139
|
return self
|
|
110
140
|
|
|
111
141
|
def __exit__(
|
|
112
142
|
self,
|
|
113
|
-
exc_type:
|
|
114
|
-
exc_val:
|
|
115
|
-
exc_tb:
|
|
143
|
+
exc_type: type[BaseException] | None,
|
|
144
|
+
exc_val: BaseException | None,
|
|
145
|
+
exc_tb: TracebackType | None,
|
|
116
146
|
) -> None:
|
|
117
147
|
self._stop_apscheduler()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import functools
|
|
2
|
+
import json
|
|
2
3
|
import os
|
|
3
4
|
import time
|
|
4
5
|
import traceback
|
|
@@ -11,7 +12,10 @@ from opentelemetry import _logs, trace
|
|
|
11
12
|
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
|
|
12
13
|
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
|
13
14
|
from opentelemetry.sdk._logs import Logger as OTELLogger
|
|
14
|
-
from opentelemetry.sdk._logs import
|
|
15
|
+
from opentelemetry.sdk._logs import (
|
|
16
|
+
LoggerProvider,
|
|
17
|
+
LogRecord,
|
|
18
|
+
)
|
|
15
19
|
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogExporter
|
|
16
20
|
from opentelemetry.sdk.resources import Attributes, Resource
|
|
17
21
|
from opentelemetry.sdk.trace import TracerProvider
|
|
@@ -32,6 +36,11 @@ def _cast_attributes(attributes: dict[str, base_t.JsonValue]) -> Attributes:
|
|
|
32
36
|
return cast(Attributes, attributes)
|
|
33
37
|
|
|
34
38
|
|
|
39
|
+
def one_line_formatter(record: LogRecord) -> str:
|
|
40
|
+
json_data = record.to_json()
|
|
41
|
+
return json.dumps(json.loads(json_data), separators=(",", ":")) + "\n"
|
|
42
|
+
|
|
43
|
+
|
|
35
44
|
@functools.cache
|
|
36
45
|
def get_otel_resource() -> Resource:
|
|
37
46
|
attributes: dict[str, base_t.JsonValue] = {
|
|
@@ -60,7 +69,9 @@ def get_otel_tracer() -> Tracer:
|
|
|
60
69
|
@functools.cache
|
|
61
70
|
def get_otel_logger() -> OTELLogger:
|
|
62
71
|
provider = LoggerProvider(resource=get_otel_resource())
|
|
63
|
-
provider.add_log_record_processor(
|
|
72
|
+
provider.add_log_record_processor(
|
|
73
|
+
BatchLogRecordProcessor(ConsoleLogExporter(formatter=one_line_formatter))
|
|
74
|
+
)
|
|
64
75
|
if get_otel_enabled():
|
|
65
76
|
provider.add_log_record_processor(BatchLogRecordProcessor(OTLPLogExporter()))
|
|
66
77
|
_logs.set_logger_provider(provider)
|
|
@@ -87,8 +98,27 @@ class Logger:
|
|
|
87
98
|
def current_trace_id(self) -> int | None:
|
|
88
99
|
return self.current_span.get_span_context().trace_id
|
|
89
100
|
|
|
90
|
-
def _patch_attributes(
|
|
91
|
-
|
|
101
|
+
def _patch_attributes(
|
|
102
|
+
self,
|
|
103
|
+
attributes: Attributes | None,
|
|
104
|
+
*,
|
|
105
|
+
message: str | None = None,
|
|
106
|
+
severity: LogSeverity | None = None,
|
|
107
|
+
) -> Attributes:
|
|
108
|
+
patched_attributes = {**(attributes if attributes is not None else {})}
|
|
109
|
+
if message is not None:
|
|
110
|
+
patched_attributes["message"] = message
|
|
111
|
+
elif "body" in patched_attributes:
|
|
112
|
+
patched_attributes["message"] = patched_attributes["body"]
|
|
113
|
+
|
|
114
|
+
if severity is not None:
|
|
115
|
+
patched_attributes["status"] = severity.lower()
|
|
116
|
+
elif "severity_text" in patched_attributes and isinstance(
|
|
117
|
+
patched_attributes["severity_text"], str
|
|
118
|
+
):
|
|
119
|
+
patched_attributes["status"] = patched_attributes["severity_text"].lower()
|
|
120
|
+
|
|
121
|
+
return patched_attributes
|
|
92
122
|
|
|
93
123
|
def _emit_log(
|
|
94
124
|
self, message: str, *, severity: LogSeverity, attributes: Attributes | None
|
|
@@ -98,7 +128,9 @@ class Logger:
|
|
|
98
128
|
body=message,
|
|
99
129
|
severity_text=severity,
|
|
100
130
|
timestamp=time.time_ns(),
|
|
101
|
-
attributes=self._patch_attributes(
|
|
131
|
+
attributes=self._patch_attributes(
|
|
132
|
+
message=message, severity=severity, attributes=attributes
|
|
133
|
+
),
|
|
102
134
|
span_id=self.current_span_id,
|
|
103
135
|
trace_id=self.current_trace_id,
|
|
104
136
|
trace_flags=DEFAULT_TRACE_OPTIONS,
|
|
@@ -131,8 +163,10 @@ class Logger:
|
|
|
131
163
|
message: str | None = None,
|
|
132
164
|
attributes: Attributes | None = None,
|
|
133
165
|
) -> None:
|
|
134
|
-
traceback_str = "".join(traceback.
|
|
135
|
-
patched_attributes = self._patch_attributes(
|
|
166
|
+
traceback_str = "".join(traceback.format_exception(exception))
|
|
167
|
+
patched_attributes = self._patch_attributes(
|
|
168
|
+
message=message, severity=LogSeverity.ERROR, attributes=attributes
|
|
169
|
+
)
|
|
136
170
|
self.current_span.record_exception(
|
|
137
171
|
exception=exception, attributes=patched_attributes
|
|
138
172
|
)
|
|
@@ -163,9 +197,17 @@ class JobLogger(Logger):
|
|
|
163
197
|
self.job_definition = job_definition
|
|
164
198
|
super().__init__(base_span)
|
|
165
199
|
|
|
166
|
-
def _patch_attributes(
|
|
200
|
+
def _patch_attributes(
|
|
201
|
+
self,
|
|
202
|
+
attributes: Attributes | None,
|
|
203
|
+
*,
|
|
204
|
+
message: str | None = None,
|
|
205
|
+
severity: LogSeverity | None = None,
|
|
206
|
+
) -> Attributes:
|
|
167
207
|
patched_attributes: dict[str, base_t.JsonValue] = {
|
|
168
|
-
**(
|
|
208
|
+
**super()._patch_attributes(
|
|
209
|
+
attributes=attributes, message=message, severity=severity
|
|
210
|
+
)
|
|
169
211
|
}
|
|
170
212
|
patched_attributes["profile.name"] = self.profile_metadata.name
|
|
171
213
|
patched_attributes["profile.base_url"] = self.profile_metadata.base_url
|
|
@@ -177,7 +219,7 @@ class JobLogger(Logger):
|
|
|
177
219
|
patched_attributes["job.definition.cron_spec"] = (
|
|
178
220
|
self.job_definition.cron_spec
|
|
179
221
|
)
|
|
180
|
-
case job_definition_t.
|
|
222
|
+
case job_definition_t.HttpJobDefinitionBase():
|
|
181
223
|
pass
|
|
182
224
|
case _:
|
|
183
225
|
assert_never(self.job_definition)
|
|
@@ -196,3 +238,14 @@ class JobLogger(Logger):
|
|
|
196
238
|
case _:
|
|
197
239
|
assert_never(self.job_definition.executor)
|
|
198
240
|
return _cast_attributes(patched_attributes)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
@contextmanager
|
|
244
|
+
def push_scope_optional(
|
|
245
|
+
logger: Logger | None, scope_name: str, *, attributes: Attributes | None = None
|
|
246
|
+
) -> Generator[None, None, None]:
|
|
247
|
+
if logger is None:
|
|
248
|
+
yield
|
|
249
|
+
else:
|
|
250
|
+
with logger.push_scope(scope_name, attributes=attributes):
|
|
251
|
+
yield
|
|
@@ -1,146 +1,71 @@
|
|
|
1
|
-
import
|
|
2
|
-
import typing
|
|
3
|
-
from dataclasses import dataclass
|
|
1
|
+
import base64
|
|
4
2
|
|
|
5
3
|
import flask
|
|
6
|
-
import simplejson
|
|
7
4
|
from flask.typing import ResponseReturnValue
|
|
8
|
-
from flask.wrappers import Response
|
|
9
5
|
from opentelemetry.trace import get_current_span
|
|
10
6
|
from uncountable.core.environment import (
|
|
11
|
-
|
|
7
|
+
get_http_server_port,
|
|
12
8
|
get_server_env,
|
|
13
|
-
get_webhook_server_port,
|
|
14
|
-
)
|
|
15
|
-
from uncountable.integration.queue_runner.command_server.command_client import (
|
|
16
|
-
send_job_queue_message,
|
|
17
|
-
)
|
|
18
|
-
from uncountable.integration.queue_runner.command_server.types import (
|
|
19
|
-
CommandServerException,
|
|
20
9
|
)
|
|
10
|
+
from uncountable.integration.executors.script_executor import resolve_script_executor
|
|
11
|
+
from uncountable.integration.http_server import GenericHttpRequest, HttpException
|
|
12
|
+
from uncountable.integration.job import CustomHttpJob, WebhookJob
|
|
21
13
|
from uncountable.integration.scan_profiles import load_profiles
|
|
22
|
-
from uncountable.integration.secret_retrieval.retrieve_secret import retrieve_secret
|
|
23
14
|
from uncountable.integration.telemetry import Logger
|
|
24
|
-
from uncountable.types import
|
|
25
|
-
|
|
26
|
-
from pkgs.argument_parser import CachedParser
|
|
15
|
+
from uncountable.types import job_definition_t
|
|
27
16
|
|
|
28
17
|
app = flask.Flask(__name__)
|
|
29
18
|
|
|
30
19
|
|
|
31
|
-
@dataclass(kw_only=True)
|
|
32
|
-
class WebhookResponse:
|
|
33
|
-
pass
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
webhook_payload_parser = CachedParser(webhook_job_t.WebhookEventBody)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class WebhookException(BaseException):
|
|
40
|
-
error_code: int
|
|
41
|
-
message: str
|
|
42
|
-
|
|
43
|
-
def __init__(self, *, error_code: int, message: str) -> None:
|
|
44
|
-
self.error_code = error_code
|
|
45
|
-
self.message = message
|
|
46
|
-
|
|
47
|
-
@staticmethod
|
|
48
|
-
def payload_failed_signature() -> "WebhookException":
|
|
49
|
-
return WebhookException(
|
|
50
|
-
error_code=401, message="webhook payload did not match signature"
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
@staticmethod
|
|
54
|
-
def no_signature_passed() -> "WebhookException":
|
|
55
|
-
return WebhookException(error_code=400, message="missing signature")
|
|
56
|
-
|
|
57
|
-
@staticmethod
|
|
58
|
-
def body_parse_error() -> "WebhookException":
|
|
59
|
-
return WebhookException(error_code=400, message="body parse error")
|
|
60
|
-
|
|
61
|
-
@staticmethod
|
|
62
|
-
def unknown_error() -> "WebhookException":
|
|
63
|
-
return WebhookException(error_code=500, message="internal server error")
|
|
64
|
-
|
|
65
|
-
def __str__(self) -> str:
|
|
66
|
-
return f"[{self.error_code}]: {self.message}"
|
|
67
|
-
|
|
68
|
-
def make_error_response(self) -> Response:
|
|
69
|
-
return Response(
|
|
70
|
-
status=self.error_code, response={"error": {"message": str(self)}}
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def _parse_webhook_payload(
|
|
75
|
-
*, raw_request_body: bytes, signature_key: str, passed_signature: str
|
|
76
|
-
) -> base_t.JsonValue:
|
|
77
|
-
request_body_signature = hmac.new(
|
|
78
|
-
signature_key.encode("utf-8"), msg=raw_request_body, digestmod="sha256"
|
|
79
|
-
).hexdigest()
|
|
80
|
-
|
|
81
|
-
if request_body_signature != passed_signature:
|
|
82
|
-
raise WebhookException.payload_failed_signature()
|
|
83
|
-
|
|
84
|
-
try:
|
|
85
|
-
request_body = simplejson.loads(raw_request_body.decode())
|
|
86
|
-
return typing.cast(base_t.JsonValue, request_body)
|
|
87
|
-
except (simplejson.JSONDecodeError, ValueError) as e:
|
|
88
|
-
raise WebhookException.body_parse_error() from e
|
|
89
|
-
|
|
90
|
-
|
|
91
20
|
def register_route(
|
|
92
21
|
*,
|
|
93
22
|
server_logger: Logger,
|
|
94
23
|
profile_meta: job_definition_t.ProfileMetadata,
|
|
95
|
-
job: job_definition_t.
|
|
24
|
+
job: job_definition_t.HttpJobDefinitionBase,
|
|
96
25
|
) -> None:
|
|
97
26
|
route = f"/{profile_meta.name}/{job.id}"
|
|
98
27
|
|
|
99
|
-
def
|
|
28
|
+
def handle_request() -> ResponseReturnValue:
|
|
100
29
|
with server_logger.push_scope(route):
|
|
101
30
|
try:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
31
|
+
if not isinstance(job.executor, job_definition_t.JobExecutorScript):
|
|
32
|
+
raise HttpException.configuration_error(
|
|
33
|
+
message="[internal] http job must use a script executor"
|
|
34
|
+
)
|
|
35
|
+
job_instance = resolve_script_executor(
|
|
36
|
+
executor=job.executor, profile_metadata=profile_meta
|
|
105
37
|
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
38
|
+
if not isinstance(job_instance, (CustomHttpJob, WebhookJob)):
|
|
39
|
+
raise HttpException.configuration_error(
|
|
40
|
+
message="[internal] http job must descend from CustomHttpJob"
|
|
41
|
+
)
|
|
42
|
+
http_request = GenericHttpRequest(
|
|
43
|
+
body_base64=base64.b64encode(flask.request.get_data()).decode(),
|
|
44
|
+
headers=dict(flask.request.headers),
|
|
109
45
|
)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
signature_key=signature_key,
|
|
116
|
-
passed_signature=passed_signature,
|
|
46
|
+
job_instance.validate_request(
|
|
47
|
+
request=http_request, job_definition=job, profile_meta=profile_meta
|
|
48
|
+
)
|
|
49
|
+
http_response = job_instance.handle_request(
|
|
50
|
+
request=http_request, job_definition=job, profile_meta=profile_meta
|
|
117
51
|
)
|
|
118
52
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
)
|
|
126
|
-
),
|
|
127
|
-
port=get_local_admin_server_port(),
|
|
128
|
-
)
|
|
129
|
-
except CommandServerException as e:
|
|
130
|
-
raise WebhookException.unknown_error() from e
|
|
131
|
-
|
|
132
|
-
return flask.jsonify(WebhookResponse())
|
|
133
|
-
except WebhookException as e:
|
|
53
|
+
return flask.make_response(
|
|
54
|
+
http_response.response,
|
|
55
|
+
http_response.status_code,
|
|
56
|
+
http_response.headers,
|
|
57
|
+
)
|
|
58
|
+
except HttpException as e:
|
|
134
59
|
server_logger.log_exception(e)
|
|
135
60
|
return e.make_error_response()
|
|
136
61
|
except Exception as e:
|
|
137
62
|
server_logger.log_exception(e)
|
|
138
|
-
return
|
|
63
|
+
return HttpException.unknown_error().make_error_response()
|
|
139
64
|
|
|
140
65
|
app.add_url_rule(
|
|
141
66
|
route,
|
|
142
|
-
endpoint=f"
|
|
143
|
-
view_func=
|
|
67
|
+
endpoint=f"handle_request_{job.id}",
|
|
68
|
+
view_func=handle_request,
|
|
144
69
|
methods=["POST"],
|
|
145
70
|
)
|
|
146
71
|
|
|
@@ -148,11 +73,13 @@ def register_route(
|
|
|
148
73
|
|
|
149
74
|
|
|
150
75
|
def main() -> None:
|
|
76
|
+
app.add_url_rule("/health", "health", lambda: ("OK", 200))
|
|
77
|
+
|
|
151
78
|
profiles = load_profiles()
|
|
152
79
|
for profile_metadata in profiles:
|
|
153
80
|
server_logger = Logger(get_current_span())
|
|
154
81
|
for job in profile_metadata.jobs:
|
|
155
|
-
if isinstance(job, job_definition_t.
|
|
82
|
+
if isinstance(job, job_definition_t.HttpJobDefinitionBase):
|
|
156
83
|
register_route(
|
|
157
84
|
server_logger=server_logger, profile_meta=profile_metadata, job=job
|
|
158
85
|
)
|
|
@@ -164,7 +91,7 @@ main()
|
|
|
164
91
|
if __name__ == "__main__":
|
|
165
92
|
app.run(
|
|
166
93
|
host="0.0.0.0",
|
|
167
|
-
port=
|
|
94
|
+
port=get_http_server_port(),
|
|
168
95
|
debug=get_server_env() == "playground",
|
|
169
96
|
exclude_patterns=[],
|
|
170
97
|
)
|
uncountable/types/__init__.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# DO NOT MODIFY -- This file is generated by type_spec
|
|
2
|
-
# flake8: noqa: F821
|
|
3
2
|
# ruff: noqa: E402 Q003
|
|
4
3
|
# fmt: off
|
|
5
4
|
# isort: skip_file
|
|
5
|
+
from .api.notebooks import add_notebook_content as add_notebook_content_t
|
|
6
6
|
from .api.recipes import add_recipe_to_project as add_recipe_to_project_t
|
|
7
|
+
from .api.recipes import add_time_series_data as add_time_series_data_t
|
|
7
8
|
from .api.recipes import archive_recipes as archive_recipes_t
|
|
8
9
|
from .api.equipment import associate_equipment_input as associate_equipment_input_t
|
|
9
10
|
from .api.recipes import associate_recipe_as_input as associate_recipe_as_input_t
|
|
@@ -16,24 +17,34 @@ from . import calculations_t as calculations_t
|
|
|
16
17
|
from . import chemical_structure_t as chemical_structure_t
|
|
17
18
|
from .api.recipes import clear_recipe_outputs as clear_recipe_outputs_t
|
|
18
19
|
from . import client_config_t as client_config_t
|
|
20
|
+
from .api.uploader import complete_async_parse as complete_async_parse_t
|
|
21
|
+
from .api.runsheet import complete_async_upload as complete_async_upload_t
|
|
19
22
|
from .api.chemical import convert_chemical_formats as convert_chemical_formats_t
|
|
20
23
|
from .api.entity import create_entities as create_entities_t
|
|
21
24
|
from .api.entity import create_entity as create_entity_t
|
|
22
25
|
from .api.inputs import create_inputs as create_inputs_t
|
|
26
|
+
from .api.recipes import create_mix_order as create_mix_order_t
|
|
27
|
+
from .api.entity import create_or_update_entity as create_or_update_entity_t
|
|
23
28
|
from .api.recipes import create_recipe as create_recipe_t
|
|
24
29
|
from .api.recipe_links import create_recipe_link as create_recipe_link_t
|
|
25
30
|
from .api.recipes import create_recipes as create_recipes_t
|
|
26
31
|
from . import curves_t as curves_t
|
|
32
|
+
from . import data_t as data_t
|
|
27
33
|
from .api.recipes import disassociate_recipe_as_input as disassociate_recipe_as_input_t
|
|
34
|
+
from .api.files import download_file as download_file_t
|
|
28
35
|
from .api.recipes import edit_recipe_inputs as edit_recipe_inputs_t
|
|
29
36
|
from . import entity_t as entity_t
|
|
30
37
|
from .api.batch import execute_batch as execute_batch_t
|
|
31
38
|
from .api.batch import execute_batch_load_async as execute_batch_load_async_t
|
|
32
39
|
from . import experiment_groups_t as experiment_groups_t
|
|
40
|
+
from .api.entity import export_entities as export_entities_t
|
|
41
|
+
from . import exports_t as exports_t
|
|
42
|
+
from .api.listing import fetch_listing as fetch_listing_t
|
|
33
43
|
from . import field_values_t as field_values_t
|
|
34
44
|
from . import fields_t as fields_t
|
|
35
45
|
from . import generic_upload_t as generic_upload_t
|
|
36
46
|
from .api.recipes import get_column_calculation_values as get_column_calculation_values_t
|
|
47
|
+
from .api.user import get_current_user_info as get_current_user_info_t
|
|
37
48
|
from .api.recipes import get_curve as get_curve_t
|
|
38
49
|
from .api.entity import get_entities_data as get_entities_data_t
|
|
39
50
|
from .api.inputs import get_input_data as get_input_data_t
|
|
@@ -42,6 +53,7 @@ from .api.inputs import get_input_names as get_input_names_t
|
|
|
42
53
|
from .api.inputs import get_inputs_data as get_inputs_data_t
|
|
43
54
|
from .api.outputs import get_output_data as get_output_data_t
|
|
44
55
|
from .api.outputs import get_output_names as get_output_names_t
|
|
56
|
+
from .api.outputs import get_output_organization as get_output_organization_t
|
|
45
57
|
from .api.project import get_projects as get_projects_t
|
|
46
58
|
from .api.project import get_projects_data as get_projects_data_t
|
|
47
59
|
from .api.recipes import get_recipe_calculations as get_recipe_calculations_t
|
|
@@ -56,18 +68,27 @@ from . import identifier_t as identifier_t
|
|
|
56
68
|
from . import input_attributes_t as input_attributes_t
|
|
57
69
|
from . import inputs_t as inputs_t
|
|
58
70
|
from . import integration_server_t as integration_server_t
|
|
71
|
+
from . import integration_session_t as integration_session_t
|
|
72
|
+
from . import integrations_t as integrations_t
|
|
59
73
|
from .api.uploader import invoke_uploader as invoke_uploader_t
|
|
60
74
|
from . import job_definition_t as job_definition_t
|
|
75
|
+
from .api.entity import list_aggregate as list_aggregate_t
|
|
61
76
|
from .api.entity import list_entities as list_entities_t
|
|
62
77
|
from .api.id_source import list_id_source as list_id_source_t
|
|
78
|
+
from . import listing_t as listing_t
|
|
63
79
|
from .api.entity import lock_entity as lock_entity_t
|
|
64
80
|
from .api.recipes import lock_recipes as lock_recipes_t
|
|
81
|
+
from .api.entity import lookup_entity as lookup_entity_t
|
|
65
82
|
from .api.id_source import match_id_source as match_id_source_t
|
|
83
|
+
from . import notices_t as notices_t
|
|
84
|
+
from . import notifications_t as notifications_t
|
|
66
85
|
from . import outputs_t as outputs_t
|
|
67
86
|
from . import overrides_t as overrides_t
|
|
68
87
|
from . import permissions_t as permissions_t
|
|
69
88
|
from . import phases_t as phases_t
|
|
70
89
|
from . import post_base_t as post_base_t
|
|
90
|
+
from .api.integrations import publish_realtime_data as publish_realtime_data_t
|
|
91
|
+
from .api.integrations import push_notification as push_notification_t
|
|
71
92
|
from . import queued_job_t as queued_job_t
|
|
72
93
|
from . import recipe_identifiers_t as recipe_identifiers_t
|
|
73
94
|
from . import recipe_inputs_t as recipe_inputs_t
|
|
@@ -77,6 +98,7 @@ from . import recipe_output_metadata_t as recipe_output_metadata_t
|
|
|
77
98
|
from . import recipe_tags_t as recipe_tags_t
|
|
78
99
|
from . import recipe_workflow_steps_t as recipe_workflow_steps_t
|
|
79
100
|
from . import recipes_t as recipes_t
|
|
101
|
+
from .api.integrations import register_sockets_token as register_sockets_token_t
|
|
80
102
|
from .api.recipes import remove_recipe_from_project as remove_recipe_from_project_t
|
|
81
103
|
from .api.recipe_links import remove_recipe_link as remove_recipe_link_t
|
|
82
104
|
from .api.entity import resolve_entity_ids as resolve_entity_ids_t
|
|
@@ -85,6 +107,7 @@ from . import response_t as response_t
|
|
|
85
107
|
from .api.triggers import run_trigger as run_trigger_t
|
|
86
108
|
from . import secret_retrieval_t as secret_retrieval_t
|
|
87
109
|
from .api.permissions import set_core_permissions as set_core_permissions_t
|
|
110
|
+
from .api.entity import set_entity_field_values as set_entity_field_values_t
|
|
88
111
|
from .api.inputs import set_input_attribute_values as set_input_attribute_values_t
|
|
89
112
|
from .api.inputs import set_input_category as set_input_category_t
|
|
90
113
|
from .api.inputs import set_input_subcategories as set_input_subcategories_t
|
|
@@ -95,13 +118,18 @@ from .api.recipes import set_recipe_output_annotations as set_recipe_output_anno
|
|
|
95
118
|
from .api.recipes import set_recipe_output_file as set_recipe_output_file_t
|
|
96
119
|
from .api.recipes import set_recipe_outputs as set_recipe_outputs_t
|
|
97
120
|
from .api.recipes import set_recipe_tags as set_recipe_tags_t
|
|
121
|
+
from .api.recipes import set_recipe_total as set_recipe_total_t
|
|
98
122
|
from .api.entity import set_values as set_values_t
|
|
123
|
+
from . import sockets_t as sockets_t
|
|
124
|
+
from . import structured_filters_t as structured_filters_t
|
|
99
125
|
from .api.entity import transition_entity_phase as transition_entity_phase_t
|
|
100
126
|
from .api.recipes import unarchive_recipes as unarchive_recipes_t
|
|
101
127
|
from . import units_t as units_t
|
|
102
128
|
from .api.entity import unlock_entity as unlock_entity_t
|
|
103
129
|
from .api.recipes import unlock_recipes as unlock_recipes_t
|
|
104
130
|
from .api.material_families import update_entity_material_families as update_entity_material_families_t
|
|
131
|
+
from . import uploader_t as uploader_t
|
|
132
|
+
from .api.condition_parameters import upsert_condition_match as upsert_condition_match_t
|
|
105
133
|
from .api.field_options import upsert_field_options as upsert_field_options_t
|
|
106
134
|
from . import users_t as users_t
|
|
107
135
|
from . import webhook_job_t as webhook_job_t
|
|
@@ -109,7 +137,9 @@ from . import workflows_t as workflows_t
|
|
|
109
137
|
|
|
110
138
|
|
|
111
139
|
__all__: list[str] = [
|
|
140
|
+
"add_notebook_content_t",
|
|
112
141
|
"add_recipe_to_project_t",
|
|
142
|
+
"add_time_series_data_t",
|
|
113
143
|
"archive_recipes_t",
|
|
114
144
|
"associate_equipment_input_t",
|
|
115
145
|
"associate_recipe_as_input_t",
|
|
@@ -122,24 +152,34 @@ __all__: list[str] = [
|
|
|
122
152
|
"chemical_structure_t",
|
|
123
153
|
"clear_recipe_outputs_t",
|
|
124
154
|
"client_config_t",
|
|
155
|
+
"complete_async_parse_t",
|
|
156
|
+
"complete_async_upload_t",
|
|
125
157
|
"convert_chemical_formats_t",
|
|
126
158
|
"create_entities_t",
|
|
127
159
|
"create_entity_t",
|
|
128
160
|
"create_inputs_t",
|
|
161
|
+
"create_mix_order_t",
|
|
162
|
+
"create_or_update_entity_t",
|
|
129
163
|
"create_recipe_t",
|
|
130
164
|
"create_recipe_link_t",
|
|
131
165
|
"create_recipes_t",
|
|
132
166
|
"curves_t",
|
|
167
|
+
"data_t",
|
|
133
168
|
"disassociate_recipe_as_input_t",
|
|
169
|
+
"download_file_t",
|
|
134
170
|
"edit_recipe_inputs_t",
|
|
135
171
|
"entity_t",
|
|
136
172
|
"execute_batch_t",
|
|
137
173
|
"execute_batch_load_async_t",
|
|
138
174
|
"experiment_groups_t",
|
|
175
|
+
"export_entities_t",
|
|
176
|
+
"exports_t",
|
|
177
|
+
"fetch_listing_t",
|
|
139
178
|
"field_values_t",
|
|
140
179
|
"fields_t",
|
|
141
180
|
"generic_upload_t",
|
|
142
181
|
"get_column_calculation_values_t",
|
|
182
|
+
"get_current_user_info_t",
|
|
143
183
|
"get_curve_t",
|
|
144
184
|
"get_entities_data_t",
|
|
145
185
|
"get_input_data_t",
|
|
@@ -148,6 +188,7 @@ __all__: list[str] = [
|
|
|
148
188
|
"get_inputs_data_t",
|
|
149
189
|
"get_output_data_t",
|
|
150
190
|
"get_output_names_t",
|
|
191
|
+
"get_output_organization_t",
|
|
151
192
|
"get_projects_t",
|
|
152
193
|
"get_projects_data_t",
|
|
153
194
|
"get_recipe_calculations_t",
|
|
@@ -162,18 +203,27 @@ __all__: list[str] = [
|
|
|
162
203
|
"input_attributes_t",
|
|
163
204
|
"inputs_t",
|
|
164
205
|
"integration_server_t",
|
|
206
|
+
"integration_session_t",
|
|
207
|
+
"integrations_t",
|
|
165
208
|
"invoke_uploader_t",
|
|
166
209
|
"job_definition_t",
|
|
210
|
+
"list_aggregate_t",
|
|
167
211
|
"list_entities_t",
|
|
168
212
|
"list_id_source_t",
|
|
213
|
+
"listing_t",
|
|
169
214
|
"lock_entity_t",
|
|
170
215
|
"lock_recipes_t",
|
|
216
|
+
"lookup_entity_t",
|
|
171
217
|
"match_id_source_t",
|
|
218
|
+
"notices_t",
|
|
219
|
+
"notifications_t",
|
|
172
220
|
"outputs_t",
|
|
173
221
|
"overrides_t",
|
|
174
222
|
"permissions_t",
|
|
175
223
|
"phases_t",
|
|
176
224
|
"post_base_t",
|
|
225
|
+
"publish_realtime_data_t",
|
|
226
|
+
"push_notification_t",
|
|
177
227
|
"queued_job_t",
|
|
178
228
|
"recipe_identifiers_t",
|
|
179
229
|
"recipe_inputs_t",
|
|
@@ -183,6 +233,7 @@ __all__: list[str] = [
|
|
|
183
233
|
"recipe_tags_t",
|
|
184
234
|
"recipe_workflow_steps_t",
|
|
185
235
|
"recipes_t",
|
|
236
|
+
"register_sockets_token_t",
|
|
186
237
|
"remove_recipe_from_project_t",
|
|
187
238
|
"remove_recipe_link_t",
|
|
188
239
|
"resolve_entity_ids_t",
|
|
@@ -191,6 +242,7 @@ __all__: list[str] = [
|
|
|
191
242
|
"run_trigger_t",
|
|
192
243
|
"secret_retrieval_t",
|
|
193
244
|
"set_core_permissions_t",
|
|
245
|
+
"set_entity_field_values_t",
|
|
194
246
|
"set_input_attribute_values_t",
|
|
195
247
|
"set_input_category_t",
|
|
196
248
|
"set_input_subcategories_t",
|
|
@@ -201,13 +253,18 @@ __all__: list[str] = [
|
|
|
201
253
|
"set_recipe_output_file_t",
|
|
202
254
|
"set_recipe_outputs_t",
|
|
203
255
|
"set_recipe_tags_t",
|
|
256
|
+
"set_recipe_total_t",
|
|
204
257
|
"set_values_t",
|
|
258
|
+
"sockets_t",
|
|
259
|
+
"structured_filters_t",
|
|
205
260
|
"transition_entity_phase_t",
|
|
206
261
|
"unarchive_recipes_t",
|
|
207
262
|
"units_t",
|
|
208
263
|
"unlock_entity_t",
|
|
209
264
|
"unlock_recipes_t",
|
|
210
265
|
"update_entity_material_families_t",
|
|
266
|
+
"uploader_t",
|
|
267
|
+
"upsert_condition_match_t",
|
|
211
268
|
"upsert_field_options_t",
|
|
212
269
|
"users_t",
|
|
213
270
|
"webhook_job_t",
|