UncountablePythonSDK 0.0.82__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 +22 -17
- 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.82.dist-info → uncountablepythonsdk-0.0.132.dist-info}/WHEEL +1 -1
- UncountablePythonSDK-0.0.82.dist-info/METADATA +0 -60
- UncountablePythonSDK-0.0.82.dist-info/RECORD +0 -292
- docs/quickstart.md +0 -19
- {UncountablePythonSDK-0.0.82.dist-info → uncountablepythonsdk-0.0.132.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from decimal import Decimal
|
|
3
|
+
|
|
4
|
+
from uncountable.integration.job import JobArguments, WebhookJob, register_job
|
|
5
|
+
from uncountable.types import (
|
|
6
|
+
base_t,
|
|
7
|
+
entity_t,
|
|
8
|
+
generic_upload_t,
|
|
9
|
+
identifier_t,
|
|
10
|
+
job_definition_t,
|
|
11
|
+
notifications_t,
|
|
12
|
+
uploader_t,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(kw_only=True)
|
|
17
|
+
class ParsePayload:
|
|
18
|
+
async_job_id: base_t.ObjectId
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@register_job
|
|
22
|
+
class ParseExample(WebhookJob[ParsePayload]):
|
|
23
|
+
def run(
|
|
24
|
+
self, args: JobArguments, payload: ParsePayload
|
|
25
|
+
) -> job_definition_t.JobResult:
|
|
26
|
+
user_id: base_t.ObjectId | None = None
|
|
27
|
+
recipe_id: base_t.ObjectId | None = None
|
|
28
|
+
file_name: str | None = None
|
|
29
|
+
data = args.client.get_entities_data(
|
|
30
|
+
entity_ids=[payload.async_job_id], entity_type=entity_t.EntityType.ASYNC_JOB
|
|
31
|
+
)
|
|
32
|
+
for field_value in data.entity_details[0].field_values:
|
|
33
|
+
if field_value.field_ref_name == "core_async_job_jobData":
|
|
34
|
+
assert isinstance(field_value.value, dict)
|
|
35
|
+
assert isinstance(field_value.value["user_id"], int)
|
|
36
|
+
user_id = field_value.value["user_id"]
|
|
37
|
+
elif (
|
|
38
|
+
field_value.field_ref_name
|
|
39
|
+
== "unc_async_job_custom_parser_recipe_ids_in_view"
|
|
40
|
+
):
|
|
41
|
+
if field_value.value is None:
|
|
42
|
+
continue
|
|
43
|
+
assert isinstance(field_value.value, list)
|
|
44
|
+
if len(field_value.value) > 0:
|
|
45
|
+
assert isinstance(field_value.value[0], int)
|
|
46
|
+
recipe_id = field_value.value[0]
|
|
47
|
+
elif field_value.field_ref_name == "unc_async_job_custom_parser_input_file":
|
|
48
|
+
assert isinstance(field_value.value, list)
|
|
49
|
+
assert len(field_value.value) == 1
|
|
50
|
+
assert isinstance(field_value.value[0], dict)
|
|
51
|
+
assert isinstance(field_value.value[0]["name"], str)
|
|
52
|
+
file_name = field_value.value[0]["name"]
|
|
53
|
+
|
|
54
|
+
assert user_id is not None
|
|
55
|
+
assert file_name is not None
|
|
56
|
+
|
|
57
|
+
dummy_parsed_file_data: list[uploader_t.ParsedFileData] = [
|
|
58
|
+
uploader_t.ParsedFileData(
|
|
59
|
+
file_name=file_name,
|
|
60
|
+
file_structures=[
|
|
61
|
+
uploader_t.DataChannel(
|
|
62
|
+
type=uploader_t.StructureElementType.CHANNEL,
|
|
63
|
+
channel=uploader_t.TextChannelData(
|
|
64
|
+
name="column1",
|
|
65
|
+
type=uploader_t.ChannelType.TEXT_CHANNEL,
|
|
66
|
+
data=[
|
|
67
|
+
uploader_t.StringValue(value="value1"),
|
|
68
|
+
uploader_t.StringValue(value="value4"),
|
|
69
|
+
uploader_t.StringValue(value="value7"),
|
|
70
|
+
],
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
uploader_t.DataChannel(
|
|
74
|
+
type=uploader_t.StructureElementType.CHANNEL,
|
|
75
|
+
channel=uploader_t.TextChannelData(
|
|
76
|
+
name="column2",
|
|
77
|
+
type=uploader_t.ChannelType.TEXT_CHANNEL,
|
|
78
|
+
data=[
|
|
79
|
+
uploader_t.StringValue(value="value2"),
|
|
80
|
+
uploader_t.StringValue(value="value5"),
|
|
81
|
+
uploader_t.StringValue(value="value8"),
|
|
82
|
+
],
|
|
83
|
+
),
|
|
84
|
+
),
|
|
85
|
+
uploader_t.DataChannel(
|
|
86
|
+
type=uploader_t.StructureElementType.CHANNEL,
|
|
87
|
+
channel=uploader_t.TextChannelData(
|
|
88
|
+
name="column3",
|
|
89
|
+
type=uploader_t.ChannelType.TEXT_CHANNEL,
|
|
90
|
+
data=[
|
|
91
|
+
uploader_t.StringValue(value="value3"),
|
|
92
|
+
uploader_t.StringValue(value="value6"),
|
|
93
|
+
uploader_t.StringValue(value="value9"),
|
|
94
|
+
],
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
uploader_t.HeaderEntry(
|
|
98
|
+
type=uploader_t.StructureElementType.HEADER,
|
|
99
|
+
value=uploader_t.TextHeaderData(
|
|
100
|
+
name="file_source",
|
|
101
|
+
type=uploader_t.HeaderType.TEXT_HEADER,
|
|
102
|
+
data=uploader_t.StringValue(value="my_file_to_upload.xlsx"),
|
|
103
|
+
),
|
|
104
|
+
),
|
|
105
|
+
uploader_t.HeaderEntry(
|
|
106
|
+
type=uploader_t.StructureElementType.HEADER,
|
|
107
|
+
value=uploader_t.NumericHeaderData(
|
|
108
|
+
name="file structure number",
|
|
109
|
+
data=uploader_t.DecimalValue(value=Decimal(99)),
|
|
110
|
+
),
|
|
111
|
+
),
|
|
112
|
+
],
|
|
113
|
+
)
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
complete_async_parse_req = args.batch_processor.complete_async_parse(
|
|
117
|
+
parsed_file_data=dummy_parsed_file_data,
|
|
118
|
+
async_job_key=identifier_t.IdentifierKeyId(id=payload.async_job_id),
|
|
119
|
+
upload_destination=generic_upload_t.UploadDestinationRecipe(
|
|
120
|
+
recipe_key=identifier_t.IdentifierKeyId(id=recipe_id or 1)
|
|
121
|
+
),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
args.batch_processor.push_notification(
|
|
125
|
+
depends_on=[complete_async_parse_req.batch_reference],
|
|
126
|
+
notification_targets=[
|
|
127
|
+
notifications_t.NotificationTargetUser(
|
|
128
|
+
user_key=identifier_t.IdentifierKeyId(id=user_id)
|
|
129
|
+
)
|
|
130
|
+
],
|
|
131
|
+
subject="Upload complete",
|
|
132
|
+
message="Your file has been uploaded",
|
|
133
|
+
display_notice=True,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
return job_definition_t.JobResult(success=True)
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def webhook_payload_type(self) -> type:
|
|
140
|
+
return ParsePayload
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import random
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from datetime import UTC, datetime
|
|
4
|
+
from decimal import Decimal
|
|
5
|
+
|
|
6
|
+
from uncountable.integration.job import JobArguments, WebhookJob, register_job
|
|
7
|
+
from uncountable.types import (
|
|
8
|
+
base_t,
|
|
9
|
+
identifier_t,
|
|
10
|
+
job_definition_t,
|
|
11
|
+
recipe_links_t,
|
|
12
|
+
set_recipe_outputs_t,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(kw_only=True)
|
|
17
|
+
class PredictionsPayload:
|
|
18
|
+
output_id: base_t.ObjectId
|
|
19
|
+
recipe_ids: list[base_t.ObjectId]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@register_job
|
|
23
|
+
class PredictionsExample(WebhookJob[PredictionsPayload]):
|
|
24
|
+
def run(
|
|
25
|
+
self, args: JobArguments, payload: PredictionsPayload
|
|
26
|
+
) -> job_definition_t.JobResult:
|
|
27
|
+
recipe_data = args.client.get_recipes_data(recipe_ids=payload.recipe_ids)
|
|
28
|
+
formatted_datetime = datetime.now(UTC).strftime("%Y-%m-%d %H:%M:%S")
|
|
29
|
+
|
|
30
|
+
for recipe in recipe_data.recipes:
|
|
31
|
+
test_sample_name = f"Predictions Model ({formatted_datetime})"
|
|
32
|
+
created_recipe_id = args.client.create_recipe(
|
|
33
|
+
name=test_sample_name,
|
|
34
|
+
material_family_id=1,
|
|
35
|
+
workflow_id=1,
|
|
36
|
+
definition_key=identifier_t.IdentifierKeyRefName(
|
|
37
|
+
ref_name="unc_test_sample"
|
|
38
|
+
),
|
|
39
|
+
).result_id
|
|
40
|
+
args.client.set_recipe_outputs(
|
|
41
|
+
output_data=[
|
|
42
|
+
set_recipe_outputs_t.RecipeOutputValue(
|
|
43
|
+
recipe_id=created_recipe_id,
|
|
44
|
+
output_id=payload.output_id,
|
|
45
|
+
experiment_num=1,
|
|
46
|
+
value_numeric=Decimal(random.random() * 10),
|
|
47
|
+
)
|
|
48
|
+
]
|
|
49
|
+
)
|
|
50
|
+
args.client.create_recipe_link(
|
|
51
|
+
recipe_from_key=identifier_t.IdentifierKeyId(id=recipe.recipe_id),
|
|
52
|
+
recipe_to_key=identifier_t.IdentifierKeyId(id=created_recipe_id),
|
|
53
|
+
link_type=recipe_links_t.RecipeLinkType.CHILD,
|
|
54
|
+
name=test_sample_name,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return job_definition_t.JobResult(success=True)
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def webhook_payload_type(self) -> type:
|
|
61
|
+
return PredictionsPayload
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from io import BytesIO
|
|
2
|
+
|
|
3
|
+
from uncountable.core.file_upload import DataFileUpload, FileUpload
|
|
4
|
+
from uncountable.integration.job import JobArguments, RunsheetWebhookJob, register_job
|
|
5
|
+
from uncountable.types import (
|
|
6
|
+
download_file_t,
|
|
7
|
+
entity_t,
|
|
8
|
+
identifier_t,
|
|
9
|
+
webhook_job_t,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@register_job
|
|
14
|
+
class StandardRunsheetGenerator(RunsheetWebhookJob):
|
|
15
|
+
def build_runsheet(
|
|
16
|
+
self,
|
|
17
|
+
*,
|
|
18
|
+
args: JobArguments,
|
|
19
|
+
payload: webhook_job_t.RunsheetWebhookPayload,
|
|
20
|
+
) -> FileUpload:
|
|
21
|
+
args.logger.log_info("Retrieving pre-exported runsheet file from async job")
|
|
22
|
+
|
|
23
|
+
file_query = download_file_t.FileDownloadQueryEntityField(
|
|
24
|
+
entity=entity_t.EntityIdentifier(
|
|
25
|
+
type=entity_t.EntityType.ASYNC_JOB,
|
|
26
|
+
identifier_key=identifier_t.IdentifierKeyId(id=payload.async_job_id),
|
|
27
|
+
),
|
|
28
|
+
field_key=identifier_t.IdentifierKeyRefName(
|
|
29
|
+
ref_name="unc_async_job_export_runsheet_recipe_export"
|
|
30
|
+
),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
downloaded_files = args.client.download_files(file_query=file_query)
|
|
34
|
+
|
|
35
|
+
file_data = downloaded_files[0].data.read()
|
|
36
|
+
return DataFileUpload(
|
|
37
|
+
data=BytesIO(file_data),
|
|
38
|
+
name=downloaded_files[0].name,
|
|
39
|
+
)
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import
|
|
1
|
+
from dataclasses import dataclass
|
|
2
2
|
|
|
3
3
|
from uncountable.integration.job import JobArguments, WebhookJob, register_job
|
|
4
|
-
from uncountable.types
|
|
4
|
+
from uncountable.types import job_definition_t
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
@
|
|
8
|
-
class
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
@dataclass(kw_only=True)
|
|
8
|
+
class ExampleWebhookPayload:
|
|
9
|
+
id: int
|
|
10
|
+
message: str
|
|
11
|
+
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
@register_job
|
|
14
|
+
class WebhookExample(WebhookJob[ExampleWebhookPayload]):
|
|
15
|
+
def run(
|
|
16
|
+
self, args: JobArguments, payload: ExampleWebhookPayload
|
|
17
|
+
) -> job_definition_t.JobResult:
|
|
14
18
|
args.logger.log_info(f"webhook invoked with payload: {payload}")
|
|
15
|
-
return JobResult(success=True)
|
|
19
|
+
return job_definition_t.JobResult(success=True)
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def webhook_payload_type(self) -> type:
|
|
23
|
+
return ExampleWebhookPayload
|
|
@@ -22,6 +22,25 @@ jobs:
|
|
|
22
22
|
- admin:
|
|
23
23
|
type: ref_name
|
|
24
24
|
ref_name: admin
|
|
25
|
+
- id: concurrent_cron_1
|
|
26
|
+
enabled: true
|
|
27
|
+
type: cron
|
|
28
|
+
name: MyConcurrentCron - 1
|
|
29
|
+
cron_spec: "* * * * *"
|
|
30
|
+
executor:
|
|
31
|
+
type: script
|
|
32
|
+
import_path: concurrent_cron
|
|
33
|
+
subqueue_name: subqueue_1
|
|
34
|
+
- id: concurrent_cron_2
|
|
35
|
+
enabled: true
|
|
36
|
+
type: cron
|
|
37
|
+
name: MyConcurrentCron - 2
|
|
38
|
+
cron_spec: "* * * * *"
|
|
39
|
+
executor:
|
|
40
|
+
type: script
|
|
41
|
+
import_path: concurrent_cron
|
|
42
|
+
subqueue_name: subqueue_2
|
|
43
|
+
|
|
25
44
|
|
|
26
45
|
- id: example_wh1
|
|
27
46
|
type: webhook
|
|
@@ -41,3 +60,45 @@ jobs:
|
|
|
41
60
|
executor:
|
|
42
61
|
type: script
|
|
43
62
|
import_path: example_wh
|
|
63
|
+
- id: example_http
|
|
64
|
+
type: custom_http
|
|
65
|
+
name: Custom HTTP
|
|
66
|
+
executor:
|
|
67
|
+
type: script
|
|
68
|
+
import_path: example_http
|
|
69
|
+
- id: example_runsheet_wh
|
|
70
|
+
type: webhook
|
|
71
|
+
name: Runsheet Webhook
|
|
72
|
+
signature_key_secret:
|
|
73
|
+
type: env
|
|
74
|
+
env_key: WH_RUNSHEET_SIGNATURE_KEY
|
|
75
|
+
executor:
|
|
76
|
+
type: script
|
|
77
|
+
import_path: example_runsheet_wh
|
|
78
|
+
- id: example_instrument
|
|
79
|
+
type: webhook
|
|
80
|
+
name: Webhook Instrument Connection
|
|
81
|
+
signature_key_secret:
|
|
82
|
+
type: env
|
|
83
|
+
env_key: WH_INSTRUMENT_SIGNATURE_KEY
|
|
84
|
+
executor:
|
|
85
|
+
type: script
|
|
86
|
+
import_path: example_instrument
|
|
87
|
+
- id: example_predictions
|
|
88
|
+
type: webhook
|
|
89
|
+
name: Webook Predictions
|
|
90
|
+
signature_key_secret:
|
|
91
|
+
type: env
|
|
92
|
+
env_key: WH_PREDICTIONS_SIGNATURE_KEY
|
|
93
|
+
executor:
|
|
94
|
+
type: script
|
|
95
|
+
import_path: example_predictions
|
|
96
|
+
- id: example_parse
|
|
97
|
+
type: webhook
|
|
98
|
+
name: Webhook Parse
|
|
99
|
+
signature_key_secret:
|
|
100
|
+
type: env
|
|
101
|
+
env_key: WH_PARSE_SIGNATURE_KEY
|
|
102
|
+
executor:
|
|
103
|
+
type: script
|
|
104
|
+
import_path: example_parse
|
|
@@ -9,14 +9,16 @@ dependencies = [
|
|
|
9
9
|
"ruff == 0.*",
|
|
10
10
|
"openpyxl == 3.*",
|
|
11
11
|
"more_itertools == 10.*",
|
|
12
|
-
"types-paramiko ==
|
|
12
|
+
"types-paramiko ==4.0.0.20250822",
|
|
13
13
|
"types-openpyxl == 3.*",
|
|
14
14
|
"types-pysftp == 0.*",
|
|
15
|
-
"types-pytz ==
|
|
15
|
+
"types-pytz ==2025.*",
|
|
16
16
|
"types-requests == 2.*",
|
|
17
17
|
"types-simplejson == 3.*",
|
|
18
18
|
"pandas-stubs",
|
|
19
|
-
"xlrd == 2.*"
|
|
19
|
+
"xlrd == 2.*",
|
|
20
|
+
"msgspec == 0.19.*",
|
|
21
|
+
"websockets==15.0.1",
|
|
20
22
|
]
|
|
21
23
|
|
|
22
24
|
[tool.mypy]
|
|
@@ -113,7 +115,6 @@ lint.ignore = [
|
|
|
113
115
|
"PD010", # .pivottable. Should add
|
|
114
116
|
"PD011", # use .to_numpy. Skip
|
|
115
117
|
"PD015", # use .merge. Should add
|
|
116
|
-
"PD901", # avoid generic df name. Skip
|
|
117
118
|
"PERF203", # avoid try except in loop. Skip
|
|
118
119
|
"PERF401", # use list comprehension. Skip
|
|
119
120
|
"PERF402", # use list.copy. Skip
|
|
@@ -173,9 +174,9 @@ lint.ignore = [
|
|
|
173
174
|
"SLOT000", # subclass of string should define slot. should add
|
|
174
175
|
"T201", # print. skip
|
|
175
176
|
"T203", # pprint. skip
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
177
|
+
"TC001", # move application import into type checking. skip
|
|
178
|
+
"TC002", # move third party import into type checking. consider
|
|
179
|
+
"TC003", # move library into type checking lbock. consider
|
|
179
180
|
"TD", # todo comments. skip
|
|
180
181
|
"TID252", # eliminate relative imports from parents. skip
|
|
181
182
|
"TRY002", # create your own exception. skip
|
|
@@ -193,11 +194,10 @@ lint.ignore = [
|
|
|
193
194
|
"RUF022", # __all__ is not sorted. skip due to isort complication
|
|
194
195
|
"UP017", # use datetime.UTC, TODO add back in
|
|
195
196
|
"UP035", # replacing List with list, TODO add back in
|
|
196
|
-
"UP038", # isinstance X | Y instead of (X, Y), TODO add back in
|
|
197
197
|
# ## FROM RUFF UPGRADE
|
|
198
198
|
"PLC2701", # private name imports. should add
|
|
199
199
|
"PLR1702", # too many nested blocks -- add with config. skip
|
|
200
|
-
"
|
|
200
|
+
"C420", # unnecessary dict comprehension. skip
|
|
201
201
|
"SIM113", # index variable should use enumerate. should add.
|
|
202
202
|
"PLR0914" # too many local variables. configure below. should add with config
|
|
203
203
|
]
|
|
@@ -212,6 +212,7 @@ exclude = [
|
|
|
212
212
|
|
|
213
213
|
[tool.ruff.lint.isort]
|
|
214
214
|
split-on-trailing-comma = true
|
|
215
|
+
known-first-party = ["pkgs"]
|
|
215
216
|
|
|
216
217
|
[tool.ruff.lint.mccabe]
|
|
217
218
|
max-complexity = 130 # goal would be to bring this down to ~50 or so
|
|
@@ -221,4 +222,3 @@ max-locals=50
|
|
|
221
222
|
|
|
222
223
|
[tool.setuptools]
|
|
223
224
|
py-modules = []
|
|
224
|
-
|
examples/oauth.py
ADDED
examples/upload_files.py
CHANGED
pkgs/argument_parser/__init__.py
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
from ._is_enum import is_string_enum_class as is_string_enum_class
|
|
1
2
|
from .argument_parser import CachedParser as CachedParser
|
|
3
|
+
from .argument_parser import ParserBase as ParserBase
|
|
4
|
+
from .argument_parser import ParserError as ParserError
|
|
5
|
+
from .argument_parser import ParserExtraFieldsError as ParserExtraFieldsError
|
|
2
6
|
from .argument_parser import ParserFunction as ParserFunction
|
|
3
7
|
from .argument_parser import ParserOptions as ParserOptions
|
|
8
|
+
from .argument_parser import SourceEncoding as SourceEncoding
|
|
4
9
|
from .argument_parser import build_parser as build_parser
|
|
10
|
+
from .argument_parser import is_missing as is_missing
|
|
11
|
+
from .argument_parser import is_optional as is_optional
|
|
12
|
+
from .argument_parser import is_union as is_union
|
|
5
13
|
from .case_convert import camel_to_snake_case as camel_to_snake_case
|
|
6
14
|
from .case_convert import kebab_to_pascal_case as kebab_to_pascal_case
|
|
7
15
|
from .case_convert import snake_to_camel_case as snake_to_camel_case
|