UncountablePythonSDK 0.0.24__py3-none-any.whl → 0.0.131__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 +60 -8
- 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 +7 -5
- examples/async_batch.py +5 -6
- examples/basic_auth.py +7 -0
- examples/create_entity.py +4 -6
- examples/create_ingredient_sdk.py +34 -0
- examples/download_files.py +26 -0
- examples/edit_recipe_inputs.py +50 -0
- examples/integration-server/jobs/materials_auto/concurrent_cron.py +11 -0
- examples/integration-server/jobs/materials_auto/example_cron.py +21 -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 +23 -0
- examples/integration-server/jobs/materials_auto/profile.yaml +104 -0
- examples/integration-server/pyproject.toml +224 -0
- examples/invoke_uploader.py +26 -0
- examples/oauth.py +7 -0
- examples/set_recipe_metadata_file.py +40 -0
- examples/set_recipe_output_file_sdk.py +26 -0
- examples/upload_files.py +2 -3
- pkgs/argument_parser/__init__.py +9 -0
- pkgs/argument_parser/_is_namedtuple.py +3 -0
- pkgs/argument_parser/argument_parser.py +295 -74
- pkgs/argument_parser/case_convert.py +4 -3
- pkgs/filesystem_utils/__init__.py +20 -0
- pkgs/filesystem_utils/_blob_session.py +144 -0
- pkgs/filesystem_utils/_gdrive_session.py +309 -0
- pkgs/filesystem_utils/_local_session.py +69 -0
- pkgs/filesystem_utils/_s3_session.py +118 -0
- pkgs/filesystem_utils/_sftp_session.py +151 -0
- pkgs/filesystem_utils/file_type_utils.py +91 -0
- pkgs/filesystem_utils/filesystem_session.py +39 -0
- pkgs/py.typed +0 -0
- pkgs/serialization/__init__.py +8 -1
- 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 +69 -54
- pkgs/serialization/serial_generic.py +16 -0
- pkgs/serialization/serial_union.py +84 -0
- pkgs/serialization/yaml.py +57 -0
- pkgs/serialization_util/__init__.py +7 -7
- pkgs/serialization_util/convert_to_snakecase.py +27 -0
- pkgs/serialization_util/dataclasses.py +14 -0
- pkgs/serialization_util/serialization_helpers.py +117 -71
- pkgs/type_spec/actions_registry/__main__.py +0 -4
- pkgs/type_spec/actions_registry/emit_typescript.py +5 -5
- pkgs/type_spec/builder.py +438 -109
- pkgs/type_spec/builder_types.py +9 -0
- pkgs/type_spec/config.py +52 -24
- pkgs/type_spec/cross_output_links.py +99 -0
- pkgs/type_spec/emit_io_ts.py +1 -1
- pkgs/type_spec/emit_open_api.py +160 -41
- pkgs/type_spec/emit_open_api_util.py +13 -7
- pkgs/type_spec/emit_python.py +450 -136
- pkgs/type_spec/emit_typescript.py +117 -250
- pkgs/type_spec/emit_typescript_util.py +293 -4
- pkgs/type_spec/load_types.py +20 -5
- 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 +13 -10
- 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 +161 -32
- 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 +4 -4
- pkgs/type_spec/value_spec/__main__.py +27 -10
- pkgs/type_spec/value_spec/convert_type.py +21 -1
- pkgs/type_spec/value_spec/emit_python.py +25 -7
- pkgs/type_spec/value_spec/types.py +1 -1
- uncountable/__init__.py +1 -2
- uncountable/core/__init__.py +11 -3
- uncountable/core/async_batch.py +16 -1
- uncountable/core/client.py +247 -52
- uncountable/core/environment.py +41 -0
- uncountable/core/file_upload.py +67 -22
- uncountable/core/types.py +8 -13
- uncountable/integration/cli.py +142 -0
- uncountable/integration/construct_client.py +43 -27
- uncountable/integration/cron.py +12 -11
- uncountable/integration/db/connect.py +12 -2
- uncountable/integration/db/session.py +25 -0
- uncountable/integration/entrypoint.py +4 -34
- uncountable/integration/executors/executors.py +147 -0
- uncountable/integration/executors/generic_upload_executor.py +336 -0
- uncountable/integration/executors/script_executor.py +15 -9
- uncountable/integration/http_server/__init__.py +5 -0
- uncountable/integration/http_server/types.py +69 -0
- uncountable/integration/job.py +246 -19
- uncountable/integration/queue_runner/__init__.py +0 -0
- uncountable/integration/queue_runner/command_server/__init__.py +28 -0
- uncountable/integration/queue_runner/command_server/command_client.py +133 -0
- uncountable/integration/queue_runner/command_server/command_server.py +142 -0
- uncountable/integration/queue_runner/command_server/constants.py +4 -0
- uncountable/integration/queue_runner/command_server/protocol/__init__.py +0 -0
- uncountable/integration/queue_runner/command_server/protocol/command_server.proto +58 -0
- uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.py +57 -0
- uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.pyi +114 -0
- uncountable/integration/queue_runner/command_server/protocol/command_server_pb2_grpc.py +264 -0
- uncountable/integration/queue_runner/command_server/types.py +75 -0
- uncountable/integration/queue_runner/datastore/__init__.py +3 -0
- uncountable/integration/queue_runner/datastore/datastore_sqlite.py +250 -0
- uncountable/integration/queue_runner/datastore/interface.py +29 -0
- uncountable/integration/queue_runner/datastore/model.py +24 -0
- uncountable/integration/queue_runner/job_scheduler.py +200 -0
- uncountable/integration/queue_runner/queue_runner.py +34 -0
- uncountable/integration/queue_runner/types.py +7 -0
- uncountable/integration/queue_runner/worker.py +116 -0
- uncountable/integration/scan_profiles.py +67 -0
- uncountable/integration/scheduler.py +199 -0
- uncountable/integration/secret_retrieval/__init__.py +3 -0
- uncountable/integration/secret_retrieval/retrieve_secret.py +93 -0
- uncountable/integration/server.py +103 -54
- uncountable/integration/telemetry.py +251 -0
- uncountable/integration/webhook_server/entrypoint.py +97 -0
- uncountable/types/__init__.py +149 -30
- uncountable/types/api/batch/execute_batch.py +16 -9
- uncountable/types/api/batch/execute_batch_load_async.py +13 -7
- uncountable/types/api/chemical/convert_chemical_formats.py +20 -8
- 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 +24 -12
- uncountable/types/api/entity/create_entity.py +22 -13
- 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 +18 -9
- uncountable/types/api/entity/grant_entity_permissions.py +48 -0
- uncountable/types/api/entity/list_aggregate.py +79 -0
- uncountable/types/api/entity/list_entities.py +53 -14
- uncountable/types/api/entity/lock_entity.py +45 -0
- uncountable/types/api/entity/lookup_entity.py +116 -0
- uncountable/types/api/entity/resolve_entity_ids.py +19 -10
- uncountable/types/api/entity/set_entity_field_values.py +44 -0
- uncountable/types/api/entity/set_values.py +15 -8
- uncountable/types/api/entity/transition_entity_phase.py +27 -12
- uncountable/types/api/entity/unlock_entity.py +44 -0
- uncountable/types/api/equipment/__init__.py +1 -0
- uncountable/types/api/equipment/associate_equipment_input.py +43 -0
- uncountable/types/api/field_options/__init__.py +1 -0
- uncountable/types/api/field_options/upsert_field_options.py +55 -0
- 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 +20 -11
- uncountable/types/api/id_source/match_id_source.py +15 -10
- uncountable/types/api/input_groups/get_input_group_names.py +16 -7
- uncountable/types/api/inputs/create_inputs.py +28 -14
- uncountable/types/api/inputs/get_input_data.py +34 -16
- uncountable/types/api/inputs/get_input_names.py +19 -10
- uncountable/types/api/inputs/get_inputs_data.py +29 -11
- uncountable/types/api/inputs/set_input_attribute_values.py +16 -10
- uncountable/types/api/inputs/set_input_category.py +44 -0
- uncountable/types/api/inputs/set_input_subcategories.py +45 -0
- uncountable/types/api/inputs/set_intermediate_type.py +50 -0
- 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/__init__.py +1 -0
- uncountable/types/api/material_families/update_entity_material_families.py +47 -0
- 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 +32 -17
- uncountable/types/api/outputs/get_output_names.py +18 -9
- uncountable/types/api/outputs/get_output_organization.py +173 -0
- uncountable/types/api/outputs/resolve_output_conditions.py +23 -11
- uncountable/types/api/permissions/set_core_permissions.py +31 -15
- uncountable/types/api/project/get_projects.py +20 -11
- uncountable/types/api/project/get_projects_data.py +23 -14
- uncountable/types/api/recipe_links/create_recipe_link.py +17 -10
- uncountable/types/api/recipe_links/remove_recipe_link.py +45 -0
- uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +19 -10
- uncountable/types/api/recipes/add_recipe_to_project.py +42 -0
- uncountable/types/api/recipes/add_time_series_data.py +64 -0
- uncountable/types/api/recipes/archive_recipes.py +14 -7
- uncountable/types/api/recipes/associate_recipe_as_input.py +16 -8
- uncountable/types/api/recipes/associate_recipe_as_lot.py +14 -7
- uncountable/types/api/recipes/clear_recipe_outputs.py +42 -0
- uncountable/types/api/recipes/create_mix_order.py +44 -0
- uncountable/types/api/recipes/create_recipe.py +21 -14
- uncountable/types/api/recipes/create_recipes.py +25 -13
- uncountable/types/api/recipes/disassociate_recipe_as_input.py +14 -7
- uncountable/types/api/recipes/edit_recipe_inputs.py +208 -19
- uncountable/types/api/recipes/get_column_calculation_values.py +57 -0
- uncountable/types/api/recipes/get_curve.py +15 -9
- uncountable/types/api/recipes/get_recipe_calculations.py +17 -11
- uncountable/types/api/recipes/get_recipe_links.py +14 -8
- uncountable/types/api/recipes/get_recipe_names.py +16 -7
- uncountable/types/api/recipes/get_recipe_output_metadata.py +16 -10
- uncountable/types/api/recipes/get_recipes_data.py +96 -45
- uncountable/types/api/recipes/lock_recipes.py +64 -0
- uncountable/types/api/recipes/remove_recipe_from_project.py +42 -0
- uncountable/types/api/recipes/set_recipe_inputs.py +19 -13
- uncountable/types/api/recipes/set_recipe_metadata.py +14 -7
- uncountable/types/api/recipes/set_recipe_output_annotations.py +114 -0
- uncountable/types/api/recipes/set_recipe_output_file.py +55 -0
- uncountable/types/api/recipes/set_recipe_outputs.py +40 -15
- uncountable/types/api/recipes/set_recipe_tags.py +30 -13
- uncountable/types/api/recipes/set_recipe_total.py +59 -0
- uncountable/types/api/recipes/unarchive_recipes.py +41 -0
- uncountable/types/api/recipes/unlock_recipes.py +51 -0
- 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 +15 -8
- uncountable/types/api/uploader/__init__.py +1 -0
- uncountable/types/api/uploader/complete_async_parse.py +46 -0
- uncountable/types/api/uploader/invoke_uploader.py +46 -0
- uncountable/types/api/user/__init__.py +1 -0
- uncountable/types/api/user/get_current_user_info.py +40 -0
- uncountable/types/async_batch.py +8 -52
- uncountable/types/async_batch_processor.py +694 -18
- uncountable/types/async_batch_t.py +108 -0
- uncountable/types/async_jobs.py +8 -0
- uncountable/types/async_jobs_t.py +52 -0
- uncountable/types/auth_retrieval.py +11 -0
- uncountable/types/auth_retrieval_t.py +75 -0
- uncountable/types/base.py +5 -80
- uncountable/types/base_t.py +87 -0
- uncountable/types/calculations.py +3 -19
- uncountable/types/calculations_t.py +26 -0
- uncountable/types/chemical_structure.py +3 -23
- uncountable/types/chemical_structure_t.py +28 -0
- uncountable/types/client_base.py +1170 -88
- uncountable/types/client_config.py +8 -0
- uncountable/types/client_config_t.py +36 -0
- uncountable/types/curves.py +5 -43
- uncountable/types/curves_t.py +50 -0
- uncountable/types/data.py +12 -0
- uncountable/types/data_t.py +103 -0
- uncountable/types/entity.py +8 -270
- uncountable/types/entity_t.py +446 -0
- uncountable/types/experiment_groups.py +3 -19
- uncountable/types/experiment_groups_t.py +26 -0
- uncountable/types/exports.py +8 -0
- uncountable/types/exports_t.py +34 -0
- uncountable/types/field_values.py +25 -61
- uncountable/types/field_values_t.py +302 -0
- uncountable/types/fields.py +3 -20
- uncountable/types/fields_t.py +27 -0
- uncountable/types/generic_upload.py +14 -0
- uncountable/types/generic_upload_t.py +119 -0
- uncountable/types/id_source.py +7 -45
- uncountable/types/id_source_t.py +68 -0
- uncountable/types/identifier.py +6 -50
- uncountable/types/identifier_t.py +62 -0
- uncountable/types/input_attributes.py +3 -25
- uncountable/types/input_attributes_t.py +29 -0
- uncountable/types/inputs.py +6 -57
- uncountable/types/inputs_t.py +82 -0
- uncountable/types/integration_server.py +8 -0
- uncountable/types/integration_server_t.py +46 -0
- 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 +28 -0
- uncountable/types/job_definition_t.py +285 -0
- 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 +3 -22
- uncountable/types/outputs_t.py +29 -0
- uncountable/types/overrides.py +9 -0
- uncountable/types/overrides_t.py +49 -0
- uncountable/types/permissions.py +3 -42
- uncountable/types/permissions_t.py +45 -0
- uncountable/types/phases.py +3 -19
- uncountable/types/phases_t.py +26 -0
- uncountable/types/post_base.py +3 -26
- uncountable/types/post_base_t.py +29 -0
- uncountable/types/queued_job.py +17 -0
- uncountable/types/queued_job_t.py +140 -0
- uncountable/types/recipe_identifiers.py +7 -58
- uncountable/types/recipe_identifiers_t.py +75 -0
- uncountable/types/recipe_inputs.py +4 -26
- uncountable/types/recipe_inputs_t.py +29 -0
- uncountable/types/recipe_links.py +4 -46
- uncountable/types/recipe_links_t.py +53 -0
- uncountable/types/recipe_metadata.py +5 -48
- uncountable/types/recipe_metadata_t.py +57 -0
- uncountable/types/recipe_output_metadata.py +3 -20
- uncountable/types/recipe_output_metadata_t.py +27 -0
- uncountable/types/recipe_tags.py +3 -19
- uncountable/types/recipe_tags_t.py +26 -0
- uncountable/types/recipe_workflow_steps.py +9 -73
- uncountable/types/recipe_workflow_steps_t.py +95 -0
- uncountable/types/recipes.py +7 -0
- uncountable/types/recipes_t.py +25 -0
- uncountable/types/response.py +3 -21
- uncountable/types/response_t.py +26 -0
- uncountable/types/secret_retrieval.py +11 -0
- uncountable/types/secret_retrieval_t.py +75 -0
- 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 +3 -19
- uncountable/types/units_t.py +26 -0
- uncountable/types/uploader.py +24 -0
- uncountable/types/uploader_t.py +222 -0
- uncountable/types/users.py +3 -20
- uncountable/types/users_t.py +27 -0
- uncountable/types/webhook_job.py +9 -0
- uncountable/types/webhook_job_t.py +48 -0
- uncountable/types/workflows.py +4 -28
- uncountable/types/workflows_t.py +38 -0
- uncountablepythonsdk-0.0.131.dist-info/METADATA +64 -0
- uncountablepythonsdk-0.0.131.dist-info/RECORD +363 -0
- {UncountablePythonSDK-0.0.24.dist-info → uncountablepythonsdk-0.0.131.dist-info}/WHEEL +1 -1
- {UncountablePythonSDK-0.0.24.dist-info → uncountablepythonsdk-0.0.131.dist-info}/top_level.txt +0 -1
- UncountablePythonSDK-0.0.24.dist-info/METADATA +0 -47
- UncountablePythonSDK-0.0.24.dist-info/RECORD +0 -216
- docs/quickstart.md +0 -19
- examples/recipe-import/importer.py +0 -39
- type_spec/external/api/batch/execute_batch.yaml +0 -56
- type_spec/external/api/batch/execute_batch_load_async.yaml +0 -18
- type_spec/external/api/chemical/convert_chemical_formats.yaml +0 -33
- type_spec/external/api/entity/create_entities.yaml +0 -45
- type_spec/external/api/entity/create_entity.yaml +0 -51
- type_spec/external/api/entity/get_entities_data.yaml +0 -29
- type_spec/external/api/entity/list_entities.yaml +0 -52
- type_spec/external/api/entity/resolve_entity_ids.yaml +0 -29
- type_spec/external/api/entity/set_values.yaml +0 -18
- type_spec/external/api/entity/transition_entity_phase.yaml +0 -44
- type_spec/external/api/id_source/list_id_source.yaml +0 -35
- type_spec/external/api/id_source/match_id_source.yaml +0 -32
- type_spec/external/api/input_groups/get_input_group_names.yaml +0 -29
- type_spec/external/api/inputs/create_inputs.yaml +0 -48
- type_spec/external/api/inputs/get_input_data.yaml +0 -95
- type_spec/external/api/inputs/get_input_names.yaml +0 -38
- type_spec/external/api/inputs/get_inputs_data.yaml +0 -82
- type_spec/external/api/inputs/set_input_attribute_values.yaml +0 -33
- type_spec/external/api/outputs/get_output_data.yaml +0 -92
- type_spec/external/api/outputs/get_output_names.yaml +0 -35
- type_spec/external/api/outputs/resolve_output_conditions.yaml +0 -50
- type_spec/external/api/permissions/set_core_permissions.yaml +0 -69
- type_spec/external/api/project/get_projects.yaml +0 -42
- type_spec/external/api/project/get_projects_data.yaml +0 -50
- type_spec/external/api/recipe_links/create_recipe_link.yaml +0 -25
- type_spec/external/api/recipe_metadata/get_recipe_metadata_data.yaml +0 -41
- type_spec/external/api/recipes/archive_recipes.yaml +0 -20
- type_spec/external/api/recipes/associate_recipe_as_input.yaml +0 -19
- type_spec/external/api/recipes/associate_recipe_as_lot.yaml +0 -19
- type_spec/external/api/recipes/create_recipe.yaml +0 -39
- type_spec/external/api/recipes/create_recipes.yaml +0 -47
- type_spec/external/api/recipes/disassociate_recipe_as_input.yaml +0 -16
- type_spec/external/api/recipes/edit_recipe_inputs.yaml +0 -85
- type_spec/external/api/recipes/get_curve.yaml +0 -21
- type_spec/external/api/recipes/get_recipe_calculations.yaml +0 -39
- type_spec/external/api/recipes/get_recipe_links.yaml +0 -26
- type_spec/external/api/recipes/get_recipe_names.yaml +0 -29
- type_spec/external/api/recipes/get_recipe_output_metadata.yaml +0 -36
- type_spec/external/api/recipes/get_recipes_data.yaml +0 -244
- type_spec/external/api/recipes/set_recipe_inputs.yaml +0 -42
- type_spec/external/api/recipes/set_recipe_metadata.yaml +0 -20
- type_spec/external/api/recipes/set_recipe_outputs.yaml +0 -52
- type_spec/external/api/recipes/set_recipe_tags.yaml +0 -62
- type_spec/external/api/triggers/run_trigger.yaml +0 -18
- uncountable/integration/types.py +0 -89
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import dataclasses
|
|
2
|
+
import typing
|
|
3
|
+
|
|
4
|
+
from .annotation import SerialBase, SerialInspector, get_serial_annotation
|
|
5
|
+
|
|
6
|
+
T = typing.TypeVar("T")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class IdentityHashWrapper(typing.Generic[T]):
|
|
10
|
+
"""This allows unhashable types to be used in the SerialUnion, like dict.
|
|
11
|
+
Since we have only one copy of the types themselves, we rely on
|
|
12
|
+
object identity for the hashing."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, inner: T) -> None:
|
|
15
|
+
self.inner = inner
|
|
16
|
+
|
|
17
|
+
def __hash__(self) -> int:
|
|
18
|
+
return id(self.inner)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclasses.dataclass(kw_only=True, frozen=True, eq=True)
|
|
22
|
+
class _SerialUnion(SerialBase):
|
|
23
|
+
"""
|
|
24
|
+
This class is to be kept private, to provide flexibility in registration/lookup.
|
|
25
|
+
Places that need the data should access it via help classes/methods.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
# If specified, indicates the Union has a discriminator which should be used to
|
|
29
|
+
# determine which type to parse.
|
|
30
|
+
discriminator: str | None = None
|
|
31
|
+
discriminator_map: IdentityHashWrapper[dict[str, type]] | None = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def serial_union_annotation(
|
|
35
|
+
*,
|
|
36
|
+
discriminator: str | None = None,
|
|
37
|
+
discriminator_map: dict[str, type] | None = None,
|
|
38
|
+
named_type_path: str | None = None,
|
|
39
|
+
is_dynamic_allowed: bool = False,
|
|
40
|
+
) -> _SerialUnion:
|
|
41
|
+
return _SerialUnion(
|
|
42
|
+
discriminator=discriminator,
|
|
43
|
+
discriminator_map=IdentityHashWrapper(discriminator_map)
|
|
44
|
+
if discriminator_map is not None
|
|
45
|
+
else None,
|
|
46
|
+
named_type_path=named_type_path,
|
|
47
|
+
from_decorator=True,
|
|
48
|
+
is_dynamic_allowed=is_dynamic_allowed,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _get_serial_union(parsed_type: type[T]) -> _SerialUnion | None:
|
|
53
|
+
serial = get_serial_annotation(parsed_type)
|
|
54
|
+
if not isinstance(serial, _SerialUnion):
|
|
55
|
+
return None
|
|
56
|
+
return serial
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class SerialClassInspector(SerialInspector[T]):
|
|
60
|
+
def __init__(self, parsed_type: type[T], serial_union: _SerialUnion) -> None:
|
|
61
|
+
super().__init__(parsed_type, serial_union)
|
|
62
|
+
self._parsed_type = parsed_type
|
|
63
|
+
self._serial_union = serial_union
|
|
64
|
+
|
|
65
|
+
def get_union_underlying(self) -> type[T]:
|
|
66
|
+
return typing.get_args(self._parsed_type)[0] # type:ignore[no-any-return]
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def discriminator(self) -> str | None:
|
|
70
|
+
return self._serial_union.discriminator
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def discriminator_map(self) -> dict[str, type] | None:
|
|
74
|
+
if self._serial_union.discriminator_map is None:
|
|
75
|
+
return None
|
|
76
|
+
return self._serial_union.discriminator_map.inner
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_serial_union_data(parsed_type: type[T]) -> SerialClassInspector[T] | None:
|
|
80
|
+
serial = _get_serial_union(parsed_type)
|
|
81
|
+
if serial is None:
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
return SerialClassInspector(parsed_type, serial)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
from typing import TYPE_CHECKING, Any
|
|
3
|
+
|
|
4
|
+
import yaml
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from _typeshed import SupportsRead as SupportsReadT
|
|
8
|
+
from _typeshed import SupportsWrite as SupportsWriteT
|
|
9
|
+
|
|
10
|
+
SupportsRead = SupportsReadT[Any]
|
|
11
|
+
SupportsWrite = SupportsWriteT[Any]
|
|
12
|
+
else:
|
|
13
|
+
SupportsRead = object
|
|
14
|
+
SupportsWrite = object
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _decimal_constructor(loader, node): # type:ignore
|
|
18
|
+
value = loader.construct_scalar(node)
|
|
19
|
+
return Decimal(value)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# A semi-acceptable patch to force a number to be parsed as a decimal, since pyyaml
|
|
23
|
+
# parses them as lossy floats otherwise. Though a bit ugly, at least this way we have
|
|
24
|
+
# support for decimal constants
|
|
25
|
+
yaml.SafeLoader.add_constructor("!decimal", _decimal_constructor)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class YAMLError(BaseException):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def dumps(obj: Any, sort_keys: bool = False) -> str:
|
|
33
|
+
return yaml.dump(obj, sort_keys=sort_keys)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def dump(obj: Any, f: SupportsWrite, sort_keys: bool = False) -> None:
|
|
37
|
+
yaml.dump(obj, f, sort_keys=sort_keys)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def safe_load(src: str | bytes | SupportsRead) -> Any:
|
|
41
|
+
try:
|
|
42
|
+
return yaml.safe_load(src)
|
|
43
|
+
except yaml.YAMLError as e:
|
|
44
|
+
raise YAMLError() from e
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def safe_dump(
|
|
48
|
+
obj: Any,
|
|
49
|
+
sort_keys: bool = False,
|
|
50
|
+
indent: int | None = None,
|
|
51
|
+
width: int | None = None,
|
|
52
|
+
) -> str:
|
|
53
|
+
return yaml.safe_dump(obj, sort_keys=sort_keys, indent=indent, width=width)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def c_load(f: SupportsRead) -> Any:
|
|
57
|
+
return yaml.load(f, Loader=yaml.CLoader)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
from .convert_to_snakecase import convert_dict_to_snake_case
|
|
2
|
+
from .dataclasses import dict_fields as dict_fields
|
|
3
|
+
from .dataclasses import iterate_fields as iterate_fields
|
|
1
4
|
from .serialization_helpers import (
|
|
2
|
-
|
|
3
|
-
convert_to_camelcase,
|
|
4
|
-
resolve_missing_to_none,
|
|
5
|
-
serialize,
|
|
5
|
+
JsonValue,
|
|
6
6
|
serialize_for_api,
|
|
7
7
|
serialize_for_storage,
|
|
8
8
|
serialize_for_storage_dict,
|
|
@@ -10,10 +10,10 @@ from .serialization_helpers import (
|
|
|
10
10
|
|
|
11
11
|
__all__: list[str] = [
|
|
12
12
|
"convert_dict_to_snake_case",
|
|
13
|
-
"convert_to_camelcase",
|
|
14
|
-
"resolve_missing_to_none",
|
|
15
|
-
"serialize",
|
|
16
13
|
"serialize_for_api",
|
|
17
14
|
"serialize_for_storage",
|
|
18
15
|
"serialize_for_storage_dict",
|
|
16
|
+
"iterate_fields",
|
|
17
|
+
"dict_fields",
|
|
18
|
+
"JsonValue",
|
|
19
19
|
]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
Any,
|
|
3
|
+
)
|
|
4
|
+
|
|
5
|
+
from pkgs.argument_parser import camel_to_snake_case
|
|
6
|
+
from pkgs.serialization import (
|
|
7
|
+
MISSING_SENTRY,
|
|
8
|
+
OpaqueKey,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _key_convert_to_snake_case(o: Any) -> Any:
|
|
13
|
+
if isinstance(o, OpaqueKey):
|
|
14
|
+
return o
|
|
15
|
+
if isinstance(o, str):
|
|
16
|
+
return camel_to_snake_case(o)
|
|
17
|
+
return o
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def convert_dict_to_snake_case(data: Any) -> Any:
|
|
21
|
+
return {
|
|
22
|
+
_key_convert_to_snake_case(k): convert_dict_to_snake_case(v)
|
|
23
|
+
if isinstance(v, dict)
|
|
24
|
+
else v
|
|
25
|
+
for k, v in data.items()
|
|
26
|
+
if v != MISSING_SENTRY
|
|
27
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from dataclasses import fields
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Iterator
|
|
3
|
+
|
|
4
|
+
if TYPE_CHECKING:
|
|
5
|
+
from _typeshed import DataclassInstance
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def iterate_fields(d: "DataclassInstance") -> Iterator[tuple[str, Any]]:
|
|
9
|
+
for field in fields(d):
|
|
10
|
+
yield field.name, getattr(d, field.name)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def dict_fields(d: "DataclassInstance") -> dict[str, Any]:
|
|
14
|
+
return dict(iterate_fields(d))
|
|
@@ -1,25 +1,31 @@
|
|
|
1
|
+
# warnings -- types here assume that keys to dictionaries are strings
|
|
2
|
+
# this is true most of the time, but there are cases where we have integer indexes
|
|
3
|
+
|
|
4
|
+
import dataclasses
|
|
1
5
|
import datetime
|
|
2
6
|
import enum
|
|
7
|
+
import functools
|
|
3
8
|
from collections.abc import Callable, Mapping, Sequence
|
|
4
9
|
from decimal import Decimal
|
|
5
10
|
from typing import (
|
|
6
11
|
TYPE_CHECKING,
|
|
7
12
|
Any,
|
|
8
|
-
|
|
13
|
+
ClassVar,
|
|
14
|
+
Protocol,
|
|
9
15
|
TypeVar,
|
|
10
16
|
Union,
|
|
17
|
+
overload,
|
|
11
18
|
)
|
|
12
19
|
|
|
13
|
-
from pkgs.argument_parser import
|
|
20
|
+
from pkgs.argument_parser import snake_to_camel_case
|
|
14
21
|
from pkgs.serialization import (
|
|
15
22
|
MISSING_SENTRY,
|
|
16
|
-
MissingSentryType,
|
|
17
|
-
MissingType,
|
|
18
23
|
OpaqueKey,
|
|
19
24
|
get_serial_class_data,
|
|
20
25
|
)
|
|
21
26
|
|
|
22
27
|
from ._get_type_for_serialization import SerializationType, get_serialization_type
|
|
28
|
+
from .dataclasses import iterate_fields
|
|
23
29
|
|
|
24
30
|
# Inlined types which otherwise would import from types/base.py
|
|
25
31
|
JsonScalar = Union[str, float, bool, Decimal, None, datetime.datetime, datetime.date]
|
|
@@ -28,53 +34,103 @@ if TYPE_CHECKING:
|
|
|
28
34
|
else:
|
|
29
35
|
JsonValue = Union[JsonScalar, dict[str, Any], list[Any]]
|
|
30
36
|
|
|
37
|
+
T = TypeVar("T")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class Dataclass(Protocol):
|
|
41
|
+
__dataclass_fields__: ClassVar[dict] # type: ignore[type-arg,unused-ignore]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def identity(x: T) -> T:
|
|
45
|
+
return x
|
|
31
46
|
|
|
32
|
-
|
|
47
|
+
|
|
48
|
+
@overload
|
|
49
|
+
def key_convert_to_camelcase(o: str) -> str: ...
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@overload
|
|
53
|
+
def key_convert_to_camelcase(o: int) -> int: ...
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def key_convert_to_camelcase(o: Any) -> str | int:
|
|
33
57
|
if isinstance(o, OpaqueKey):
|
|
34
58
|
return o
|
|
35
|
-
if isinstance(o, enum.
|
|
59
|
+
if isinstance(o, enum.StrEnum):
|
|
36
60
|
return o.value
|
|
37
61
|
if isinstance(o, str):
|
|
38
62
|
return snake_to_camel_case(o)
|
|
39
|
-
|
|
63
|
+
if isinstance(o, int):
|
|
64
|
+
# we allow dictionaries to use integer keys
|
|
65
|
+
return o
|
|
66
|
+
raise ValueError("Unexpected key type", o)
|
|
40
67
|
|
|
41
68
|
|
|
42
|
-
def _convert_dict(d: Any) ->
|
|
69
|
+
def _convert_dict(d: dict[str, Any]) -> dict[str, JsonValue]:
|
|
43
70
|
return {
|
|
44
|
-
key_convert_to_camelcase(k):
|
|
71
|
+
key_convert_to_camelcase(k): serialize_for_api(v)
|
|
45
72
|
for k, v in d.items()
|
|
46
73
|
if v != MISSING_SENTRY
|
|
47
74
|
}
|
|
48
75
|
|
|
49
76
|
|
|
50
|
-
def _serialize_dict(d: Any) -> dict[str,
|
|
51
|
-
return {k:
|
|
77
|
+
def _serialize_dict(d: dict[str, Any]) -> dict[str, JsonValue]:
|
|
78
|
+
return {k: serialize_for_storage(v) for k, v in d.items() if v != MISSING_SENTRY}
|
|
52
79
|
|
|
53
80
|
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
|
|
81
|
+
def _serialize_dataclass(d: Any) -> dict[str, JsonValue]:
|
|
82
|
+
return {
|
|
83
|
+
k: serialize_for_storage(v) for k, v in iterate_fields(d) if v != MISSING_SENTRY
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _to_string_value(value: Any) -> str:
|
|
88
|
+
assert isinstance(value, (Decimal, int)), (
|
|
89
|
+
f"Expecting decimal or int, received: {value} (type={type(value)})"
|
|
90
|
+
)
|
|
91
|
+
return str(value)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@dataclasses.dataclass(kw_only=True)
|
|
95
|
+
class DataclassConversions:
|
|
96
|
+
key_conversions: dict[str, str]
|
|
97
|
+
value_conversion_functions: dict[str, Callable[[Any], JsonValue]]
|
|
57
98
|
|
|
58
|
-
|
|
99
|
+
|
|
100
|
+
@functools.lru_cache(maxsize=10000)
|
|
101
|
+
def _get_dataclass_conversion_lookups(dataclass_type: Any) -> DataclassConversions:
|
|
102
|
+
scd = get_serial_class_data(dataclass_type)
|
|
103
|
+
|
|
104
|
+
key_conversions: dict[str, str] = {}
|
|
105
|
+
value_conversion_functions: dict[str, Callable[[Any], JsonValue]] = {}
|
|
106
|
+
|
|
107
|
+
for field in dataclasses.fields(dataclass_type):
|
|
108
|
+
key = field.name
|
|
59
109
|
if scd.has_unconverted_key(key):
|
|
60
|
-
|
|
61
|
-
|
|
110
|
+
key_conversions[key] = key
|
|
111
|
+
else:
|
|
112
|
+
key_conversions[key] = key_convert_to_camelcase(key)
|
|
62
113
|
|
|
63
|
-
def value_convert(key: Any, value: Any) -> Any:
|
|
64
|
-
if value is None:
|
|
65
|
-
return None
|
|
66
114
|
if scd.has_to_string_value(key):
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return value
|
|
73
|
-
return convert_to_camelcase(value)
|
|
115
|
+
value_conversion_functions[key] = _to_string_value
|
|
116
|
+
elif scd.has_unconverted_value(key):
|
|
117
|
+
value_conversion_functions[key] = serialize_for_storage
|
|
118
|
+
else:
|
|
119
|
+
value_conversion_functions[key] = serialize_for_api
|
|
74
120
|
|
|
121
|
+
return DataclassConversions(
|
|
122
|
+
key_conversions=key_conversions,
|
|
123
|
+
value_conversion_functions=value_conversion_functions,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _convert_dataclass(d: Any) -> dict[str, JsonValue]:
|
|
128
|
+
conversions = _get_dataclass_conversion_lookups(type(d)) # type: ignore[arg-type]
|
|
75
129
|
return {
|
|
76
|
-
|
|
77
|
-
|
|
130
|
+
conversions.key_conversions[k]: (
|
|
131
|
+
conversions.value_conversion_functions[k](v) if v is not None else None
|
|
132
|
+
)
|
|
133
|
+
for k, v in iterate_fields(d)
|
|
78
134
|
if v != MISSING_SENTRY
|
|
79
135
|
}
|
|
80
136
|
|
|
@@ -83,38 +139,54 @@ _SERIALIZATION_FUNCS_STANDARD = {
|
|
|
83
139
|
SerializationType.ENUM: lambda x: str(x.value),
|
|
84
140
|
SerializationType.DATE: lambda x: x.isoformat(),
|
|
85
141
|
SerializationType.TIMEDELTA: lambda x: x.total_seconds(),
|
|
86
|
-
SerializationType.UNKNOWN:
|
|
142
|
+
SerializationType.UNKNOWN: identity,
|
|
87
143
|
}
|
|
88
144
|
|
|
89
|
-
_CONVERSION_SERIALIZATION_FUNCS = {
|
|
145
|
+
_CONVERSION_SERIALIZATION_FUNCS: dict[SerializationType, Callable[[Any], JsonValue]] = {
|
|
90
146
|
**_SERIALIZATION_FUNCS_STANDARD,
|
|
91
147
|
SerializationType.NAMED_TUPLE: lambda x: _convert_dict(x._asdict()),
|
|
92
|
-
SerializationType.ITERABLE: lambda x: [
|
|
148
|
+
SerializationType.ITERABLE: lambda x: [serialize_for_api(v) for v in x],
|
|
93
149
|
SerializationType.DICT: _convert_dict,
|
|
94
150
|
SerializationType.DATACLASS: _convert_dataclass,
|
|
95
151
|
}
|
|
96
152
|
|
|
97
153
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
154
|
+
@overload
|
|
155
|
+
def serialize_for_api(obj: None) -> None: ...
|
|
156
|
+
|
|
101
157
|
|
|
158
|
+
@overload
|
|
159
|
+
def serialize_for_api(obj: dict[str, Any]) -> dict[str, JsonValue]: ...
|
|
102
160
|
|
|
103
|
-
|
|
161
|
+
|
|
162
|
+
@overload
|
|
163
|
+
def serialize_for_api(obj: Dataclass) -> dict[str, JsonValue]: ...
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@overload
|
|
167
|
+
def serialize_for_api(obj: Any) -> JsonValue: ...
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def serialize_for_api(obj: Any) -> JsonValue:
|
|
104
171
|
"""
|
|
105
172
|
Serialize to a parsed-JSON format suitably encoded for API output.
|
|
106
173
|
|
|
107
174
|
Use the CachedParser.parse_api to parse this data.
|
|
108
175
|
"""
|
|
109
176
|
serialization_type = get_serialization_type(type(obj)) # type: ignore
|
|
110
|
-
|
|
177
|
+
if (
|
|
178
|
+
serialization_type == SerializationType.UNKNOWN
|
|
179
|
+
): # performance optimization to not do function lookup
|
|
180
|
+
return obj # type: ignore
|
|
181
|
+
r = _CONVERSION_SERIALIZATION_FUNCS[serialization_type](obj)
|
|
182
|
+
return r
|
|
111
183
|
|
|
112
184
|
|
|
113
185
|
_SERIALIZATION_FUNCS_DICT: dict[
|
|
114
186
|
SerializationType, Callable[[Any], dict[str, JsonValue]]
|
|
115
187
|
] = {
|
|
116
188
|
SerializationType.DICT: _serialize_dict,
|
|
117
|
-
SerializationType.DATACLASS:
|
|
189
|
+
SerializationType.DATACLASS: _serialize_dataclass,
|
|
118
190
|
}
|
|
119
191
|
|
|
120
192
|
|
|
@@ -122,15 +194,10 @@ _SERIALIZATION_FUNCS: dict[SerializationType, Callable[[Any], JsonValue]] = {
|
|
|
122
194
|
**_SERIALIZATION_FUNCS_STANDARD,
|
|
123
195
|
**_SERIALIZATION_FUNCS_DICT,
|
|
124
196
|
SerializationType.NAMED_TUPLE: lambda x: _serialize_dict(x._asdict()),
|
|
125
|
-
SerializationType.ITERABLE: lambda x: [
|
|
197
|
+
SerializationType.ITERABLE: lambda x: [serialize_for_storage(v) for v in x],
|
|
126
198
|
}
|
|
127
199
|
|
|
128
200
|
|
|
129
|
-
def serialize(obj: Any) -> Any:
|
|
130
|
-
"""@DEPRECATED: prefer serialize_for_storage"""
|
|
131
|
-
return serialize_for_storage(obj)
|
|
132
|
-
|
|
133
|
-
|
|
134
201
|
def serialize_for_storage(obj: Any) -> JsonValue:
|
|
135
202
|
"""
|
|
136
203
|
Convert a value into the pseudo-JSON form for
|
|
@@ -139,37 +206,16 @@ def serialize_for_storage(obj: Any) -> JsonValue:
|
|
|
139
206
|
Use the CachedParser.parse_storage to parse this data.
|
|
140
207
|
"""
|
|
141
208
|
serialization_type = get_serialization_type(type(obj)) # type: ignore
|
|
209
|
+
if (
|
|
210
|
+
serialization_type == SerializationType.UNKNOWN
|
|
211
|
+
): # performance optimization to not do function lookup
|
|
212
|
+
return obj # type: ignore
|
|
142
213
|
return _SERIALIZATION_FUNCS[serialization_type](obj)
|
|
143
214
|
|
|
144
215
|
|
|
145
|
-
def serialize_for_storage_dict(obj:
|
|
216
|
+
def serialize_for_storage_dict(obj: dict | Dataclass) -> dict[str, JsonValue]: # type: ignore[type-arg]
|
|
146
217
|
"""
|
|
147
218
|
Same as serialize for storage but guarantees outer object is a dictionary
|
|
148
219
|
"""
|
|
149
|
-
serialization_type = get_serialization_type(type(obj))
|
|
220
|
+
serialization_type = get_serialization_type(type(obj))
|
|
150
221
|
return _SERIALIZATION_FUNCS_DICT[serialization_type](obj)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def key_convert_to_snake_case(o: Any) -> Any:
|
|
154
|
-
if isinstance(o, OpaqueKey):
|
|
155
|
-
return o
|
|
156
|
-
if isinstance(o, str):
|
|
157
|
-
return camel_to_snake_case(o)
|
|
158
|
-
return o
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
def convert_dict_to_snake_case(data: Any) -> Any:
|
|
162
|
-
return {
|
|
163
|
-
key_convert_to_snake_case(k): convert_dict_to_snake_case(v)
|
|
164
|
-
if isinstance(v, dict)
|
|
165
|
-
else v
|
|
166
|
-
for k, v in data.items()
|
|
167
|
-
if v != MISSING_SENTRY
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
T = TypeVar("T")
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def resolve_missing_to_none(val: MissingType[T]) -> Optional[T]:
|
|
175
|
-
return val if not isinstance(val, MissingSentryType) else None
|
|
@@ -6,7 +6,6 @@ import os
|
|
|
6
6
|
import sys
|
|
7
7
|
from collections import defaultdict
|
|
8
8
|
from dataclasses import dataclass
|
|
9
|
-
from typing import TypeVar
|
|
10
9
|
|
|
11
10
|
from main.base.types import actions_registry_t
|
|
12
11
|
from pkgs.type_spec import builder
|
|
@@ -22,9 +21,6 @@ key_short_description = "short_description"
|
|
|
22
21
|
key_description = "description"
|
|
23
22
|
|
|
24
23
|
|
|
25
|
-
TypeT = TypeVar("TypeT")
|
|
26
|
-
|
|
27
|
-
|
|
28
24
|
class InvalidSpecException(Exception):
|
|
29
25
|
pass
|
|
30
26
|
|
|
@@ -64,7 +64,7 @@ def _emit_imports(
|
|
|
64
64
|
sorted([f"type {_action_namespace_name(item)}" for item in list(namespaces)])
|
|
65
65
|
)
|
|
66
66
|
out.write(
|
|
67
|
-
f'import {{ ActionsRegistryT, {namespaces_to_import} }} from "
|
|
67
|
+
f'import {{ ActionsRegistryT, {namespaces_to_import} }} from "unc_types"\n\n'
|
|
68
68
|
)
|
|
69
69
|
out.write(MODIFY_NOTICE)
|
|
70
70
|
return out.getvalue()
|
|
@@ -111,9 +111,7 @@ def _get_argument_type(arguments: str | None) -> str | None:
|
|
|
111
111
|
argument_parts = arguments.split(".")
|
|
112
112
|
namespace = argument_parts[0]
|
|
113
113
|
type_name = argument_parts[1]
|
|
114
|
-
|
|
115
|
-
return f"{_action_namespace_name(namespace)}.{type_name}"
|
|
116
|
-
return None
|
|
114
|
+
return f"{_action_namespace_name(namespace)}.{type_name}"
|
|
117
115
|
|
|
118
116
|
|
|
119
117
|
def _emit_action_definition(
|
|
@@ -129,7 +127,9 @@ def _emit_action_definition(
|
|
|
129
127
|
out.write(f"{indent}{_action_symbol_name(action_definition)}: {{\n")
|
|
130
128
|
out.write(f"{sub_indent}name: {encode_common_string(action_definition.name)},\n")
|
|
131
129
|
if action_definition.icon is not None:
|
|
132
|
-
out.write(
|
|
130
|
+
out.write(
|
|
131
|
+
f"{sub_indent}icon: {encode_common_string(action_definition.icon)},\n"
|
|
132
|
+
)
|
|
133
133
|
out.write(
|
|
134
134
|
f"{sub_indent}shortDescription: {encode_common_string(action_definition.short_description)},\n"
|
|
135
135
|
)
|