UncountablePythonSDK 0.0.52__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 +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/async_batch.py +3 -3
- examples/basic_auth.py +7 -0
- examples/create_entity.py +3 -1
- examples/create_ingredient_sdk.py +34 -0
- examples/download_files.py +26 -0
- examples/edit_recipe_inputs.py +4 -2
- 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 +4 -1
- 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 +1 -2
- pkgs/argument_parser/__init__.py +9 -0
- pkgs/argument_parser/_is_namedtuple.py +3 -0
- pkgs/argument_parser/argument_parser.py +217 -70
- pkgs/filesystem_utils/__init__.py +1 -0
- pkgs/filesystem_utils/_blob_session.py +144 -0
- pkgs/filesystem_utils/_gdrive_session.py +10 -7
- pkgs/filesystem_utils/_s3_session.py +15 -13
- pkgs/filesystem_utils/_sftp_session.py +11 -7
- pkgs/filesystem_utils/file_type_utils.py +30 -10
- pkgs/py.typed +0 -0
- 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 +47 -26
- pkgs/serialization/serial_generic.py +16 -0
- pkgs/serialization/serial_union.py +17 -14
- pkgs/serialization/yaml.py +4 -1
- 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 +5 -5
- pkgs/type_spec/builder.py +354 -119
- pkgs/type_spec/builder_types.py +9 -0
- pkgs/type_spec/config.py +51 -11
- 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 +127 -36
- pkgs/type_spec/emit_open_api_util.py +5 -6
- pkgs/type_spec/emit_python.py +329 -121
- pkgs/type_spec/emit_typescript.py +117 -256
- pkgs/type_spec/emit_typescript_util.py +291 -2
- pkgs/type_spec/load_types.py +18 -4
- 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 +124 -29
- 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 +26 -9
- 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/core/async_batch.py +1 -1
- uncountable/core/client.py +142 -39
- uncountable/core/environment.py +41 -0
- uncountable/core/file_upload.py +52 -18
- uncountable/integration/cli.py +142 -0
- uncountable/integration/construct_client.py +8 -8
- uncountable/integration/cron.py +11 -37
- uncountable/integration/db/connect.py +12 -2
- uncountable/integration/db/session.py +25 -0
- uncountable/integration/entrypoint.py +8 -37
- uncountable/integration/executors/executors.py +125 -2
- uncountable/integration/executors/generic_upload_executor.py +87 -29
- uncountable/integration/executors/script_executor.py +3 -3
- uncountable/integration/http_server/__init__.py +5 -0
- uncountable/integration/http_server/types.py +69 -0
- uncountable/integration/job.py +242 -12
- 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/retrieve_secret.py +26 -4
- uncountable/integration/server.py +94 -69
- uncountable/integration/telemetry.py +150 -34
- uncountable/integration/webhook_server/entrypoint.py +97 -0
- uncountable/types/__init__.py +78 -1
- uncountable/types/api/batch/execute_batch.py +13 -6
- uncountable/types/api/batch/execute_batch_load_async.py +9 -3
- uncountable/types/api/chemical/convert_chemical_formats.py +17 -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 +19 -7
- uncountable/types/api/entity/create_entity.py +17 -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 +13 -4
- 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 +42 -10
- uncountable/types/api/entity/lock_entity.py +11 -4
- uncountable/types/api/entity/lookup_entity.py +116 -0
- uncountable/types/api/entity/resolve_entity_ids.py +15 -6
- uncountable/types/api/entity/set_entity_field_values.py +44 -0
- uncountable/types/api/entity/set_values.py +10 -3
- uncountable/types/api/entity/transition_entity_phase.py +22 -7
- uncountable/types/api/entity/unlock_entity.py +10 -3
- uncountable/types/api/equipment/associate_equipment_input.py +9 -3
- uncountable/types/api/field_options/upsert_field_options.py +17 -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 +16 -7
- uncountable/types/api/id_source/match_id_source.py +14 -5
- uncountable/types/api/input_groups/get_input_group_names.py +13 -4
- uncountable/types/api/inputs/create_inputs.py +23 -9
- uncountable/types/api/inputs/get_input_data.py +30 -12
- uncountable/types/api/inputs/get_input_names.py +16 -7
- uncountable/types/api/inputs/get_inputs_data.py +25 -7
- uncountable/types/api/inputs/set_input_attribute_values.py +12 -6
- uncountable/types/api/inputs/set_input_category.py +12 -5
- uncountable/types/api/inputs/set_input_subcategories.py +10 -3
- uncountable/types/api/inputs/set_intermediate_type.py +11 -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 +10 -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 +28 -13
- uncountable/types/api/outputs/get_output_names.py +15 -6
- uncountable/types/api/outputs/get_output_organization.py +173 -0
- uncountable/types/api/outputs/resolve_output_conditions.py +20 -8
- uncountable/types/api/permissions/set_core_permissions.py +26 -10
- uncountable/types/api/project/get_projects.py +16 -7
- uncountable/types/api/project/get_projects_data.py +17 -8
- uncountable/types/api/recipe_links/create_recipe_link.py +12 -5
- uncountable/types/api/recipe_links/remove_recipe_link.py +11 -4
- uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +16 -7
- uncountable/types/api/recipes/add_recipe_to_project.py +10 -3
- uncountable/types/api/recipes/add_time_series_data.py +64 -0
- uncountable/types/api/recipes/archive_recipes.py +11 -4
- uncountable/types/api/recipes/associate_recipe_as_input.py +12 -5
- uncountable/types/api/recipes/associate_recipe_as_lot.py +10 -3
- 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 +15 -9
- uncountable/types/api/recipes/create_recipes.py +21 -9
- uncountable/types/api/recipes/disassociate_recipe_as_input.py +10 -3
- uncountable/types/api/recipes/edit_recipe_inputs.py +134 -22
- uncountable/types/api/recipes/get_column_calculation_values.py +57 -0
- uncountable/types/api/recipes/get_curve.py +11 -5
- uncountable/types/api/recipes/get_recipe_calculations.py +13 -7
- uncountable/types/api/recipes/get_recipe_links.py +10 -4
- uncountable/types/api/recipes/get_recipe_names.py +13 -4
- uncountable/types/api/recipes/get_recipe_output_metadata.py +12 -6
- uncountable/types/api/recipes/get_recipes_data.py +87 -33
- uncountable/types/api/recipes/lock_recipes.py +19 -8
- uncountable/types/api/recipes/remove_recipe_from_project.py +10 -3
- uncountable/types/api/recipes/set_recipe_inputs.py +16 -10
- uncountable/types/api/recipes/set_recipe_metadata.py +10 -3
- uncountable/types/api/recipes/set_recipe_output_annotations.py +24 -12
- uncountable/types/api/recipes/set_recipe_output_file.py +55 -0
- uncountable/types/api/recipes/set_recipe_outputs.py +35 -12
- uncountable/types/api/recipes/set_recipe_tags.py +26 -9
- uncountable/types/api/recipes/set_recipe_total.py +59 -0
- uncountable/types/api/recipes/unarchive_recipes.py +10 -3
- uncountable/types/api/recipes/unlock_recipes.py +14 -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 +11 -4
- uncountable/types/api/uploader/complete_async_parse.py +46 -0
- uncountable/types/api/uploader/invoke_uploader.py +13 -6
- uncountable/types/api/user/__init__.py +1 -0
- uncountable/types/api/user/get_current_user_info.py +40 -0
- uncountable/types/async_batch.py +2 -1
- uncountable/types/async_batch_processor.py +618 -18
- uncountable/types/async_batch_t.py +54 -7
- 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 +0 -1
- uncountable/types/base_t.py +13 -11
- uncountable/types/calculations.py +0 -1
- uncountable/types/calculations_t.py +5 -2
- uncountable/types/chemical_structure.py +0 -1
- uncountable/types/chemical_structure_t.py +6 -5
- uncountable/types/client_base.py +751 -70
- uncountable/types/client_config.py +1 -1
- uncountable/types/client_config_t.py +17 -3
- uncountable/types/curves.py +0 -1
- uncountable/types/curves_t.py +10 -7
- uncountable/types/data.py +12 -0
- uncountable/types/data_t.py +103 -0
- uncountable/types/entity.py +4 -1
- uncountable/types/entity_t.py +125 -7
- uncountable/types/experiment_groups.py +0 -1
- uncountable/types/experiment_groups_t.py +5 -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 +246 -9
- uncountable/types/fields.py +0 -1
- uncountable/types/fields_t.py +5 -2
- uncountable/types/generic_upload.py +6 -1
- uncountable/types/generic_upload_t.py +88 -9
- uncountable/types/id_source.py +0 -1
- uncountable/types/id_source_t.py +26 -7
- uncountable/types/identifier.py +0 -1
- uncountable/types/identifier_t.py +13 -5
- uncountable/types/input_attributes.py +0 -1
- uncountable/types/input_attributes_t.py +4 -4
- uncountable/types/inputs.py +1 -1
- uncountable/types/inputs_t.py +24 -4
- 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 +4 -6
- uncountable/types/job_definition_t.py +96 -65
- 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 +6 -3
- uncountable/types/overrides.py +9 -0
- uncountable/types/overrides_t.py +49 -0
- uncountable/types/permissions.py +0 -1
- uncountable/types/permissions_t.py +1 -2
- uncountable/types/phases.py +0 -1
- uncountable/types/phases_t.py +5 -2
- uncountable/types/post_base.py +0 -1
- uncountable/types/post_base_t.py +1 -2
- uncountable/types/queued_job.py +17 -0
- uncountable/types/queued_job_t.py +140 -0
- uncountable/types/recipe_identifiers.py +0 -1
- uncountable/types/recipe_identifiers_t.py +21 -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 +7 -4
- uncountable/types/recipe_metadata.py +0 -1
- uncountable/types/recipe_metadata_t.py +14 -9
- uncountable/types/recipe_output_metadata.py +0 -1
- uncountable/types/recipe_output_metadata_t.py +5 -2
- uncountable/types/recipe_tags.py +0 -1
- uncountable/types/recipe_tags_t.py +5 -2
- uncountable/types/recipe_workflow_steps.py +0 -1
- uncountable/types/recipe_workflow_steps_t.py +14 -7
- uncountable/types/recipes.py +0 -1
- uncountable/types/recipes_t.py +6 -2
- uncountable/types/response.py +0 -1
- uncountable/types/response_t.py +3 -2
- uncountable/types/secret_retrieval.py +0 -1
- uncountable/types/secret_retrieval_t.py +13 -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 +5 -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 +5 -2
- uncountable/types/webhook_job.py +9 -0
- uncountable/types/webhook_job_t.py +48 -0
- uncountable/types/workflows.py +0 -1
- uncountable/types/workflows_t.py +10 -4
- uncountablepythonsdk-0.0.131.dist-info/METADATA +64 -0
- uncountablepythonsdk-0.0.131.dist-info/RECORD +363 -0
- {UncountablePythonSDK-0.0.52.dist-info → uncountablepythonsdk-0.0.131.dist-info}/WHEEL +1 -1
- UncountablePythonSDK-0.0.52.dist-info/METADATA +0 -56
- UncountablePythonSDK-0.0.52.dist-info/RECORD +0 -246
- docs/quickstart.md +0 -19
- uncountable/core/version.py +0 -11
- {UncountablePythonSDK-0.0.52.dist-info → uncountablepythonsdk-0.0.131.dist-info}/top_level.txt +0 -0
|
@@ -3,21 +3,21 @@ import dataclasses
|
|
|
3
3
|
import decimal
|
|
4
4
|
import io
|
|
5
5
|
import json
|
|
6
|
-
from
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import Any, cast
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
import yaml
|
|
10
|
+
|
|
11
|
+
from main.base.types import data_t, type_info_t
|
|
9
12
|
from main.base.types.base_t import PureJsonValue
|
|
10
13
|
from pkgs.argument_parser import CachedParser
|
|
11
|
-
from pkgs.serialization_util import
|
|
12
|
-
serialize_for_api,
|
|
13
|
-
serialize_for_storage,
|
|
14
|
-
)
|
|
14
|
+
from pkgs.serialization_util import serialize_for_api, serialize_for_storage
|
|
15
15
|
|
|
16
16
|
from .. import builder, util
|
|
17
17
|
from ..emit_typescript_util import MODIFY_NOTICE, ts_name
|
|
18
18
|
from ..value_spec import convert_to_value_spec_type
|
|
19
19
|
|
|
20
|
-
ext_info_parser = CachedParser(
|
|
20
|
+
ext_info_parser = CachedParser(type_info_t.ExtInfo, strict_property_parsing=True)
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def type_path_of(stype: builder.SpecType) -> object: # NamePath
|
|
@@ -41,10 +41,23 @@ def type_path_of(stype: builder.SpecType) -> object: # NamePath
|
|
|
41
41
|
parts: list[object] = ["$literal"]
|
|
42
42
|
for parameter in stype.parameters:
|
|
43
43
|
assert isinstance(parameter, builder.SpecTypeLiteralWrapper)
|
|
44
|
+
emit_value = parameter.value
|
|
45
|
+
if isinstance(parameter.value_type, builder.SpecTypeDefnObject):
|
|
46
|
+
emit_value = parameter.value
|
|
47
|
+
assert isinstance(emit_value, (str, bool)), (
|
|
48
|
+
f"invalid-literal-value:{emit_value}"
|
|
49
|
+
)
|
|
50
|
+
elif isinstance(parameter.value_type, builder.SpecTypeDefnStringEnum):
|
|
51
|
+
key = parameter.value
|
|
52
|
+
assert isinstance(key, str)
|
|
53
|
+
emit_value = parameter.value_type.values[key].value
|
|
54
|
+
else:
|
|
55
|
+
raise Exception("unhandled-literal-type")
|
|
56
|
+
|
|
44
57
|
# This allows expansion to enum literal values later
|
|
45
58
|
parts.append([
|
|
46
59
|
"$value",
|
|
47
|
-
|
|
60
|
+
emit_value,
|
|
48
61
|
type_path_of(parameter.value_type),
|
|
49
62
|
])
|
|
50
63
|
return parts
|
|
@@ -95,6 +108,35 @@ def emit_type_info(build: builder.SpecBuilder, output: str) -> None:
|
|
|
95
108
|
util.rewrite_file(f"{output}/type_map.ts", type_map_out.getvalue())
|
|
96
109
|
|
|
97
110
|
|
|
111
|
+
def _convert_value_for_yaml_dump(value: Any) -> Any:
|
|
112
|
+
if isinstance(value, Enum):
|
|
113
|
+
return value.value
|
|
114
|
+
elif isinstance(value, list):
|
|
115
|
+
return [_convert_value_for_yaml_dump(item) for item in value]
|
|
116
|
+
elif isinstance(value, dict):
|
|
117
|
+
return {k: _convert_value_for_yaml_dump(v) for k, v in value.items()}
|
|
118
|
+
elif isinstance(value, decimal.Decimal):
|
|
119
|
+
return str(value)
|
|
120
|
+
else:
|
|
121
|
+
return value
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def asdict_for_yaml_dump(dataclass_instance: Any) -> Any:
|
|
125
|
+
return {
|
|
126
|
+
k: _convert_value_for_yaml_dump(v)
|
|
127
|
+
for k, v in dataclasses.asdict(dataclass_instance).items()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def emit_type_info_python(build: builder.SpecBuilder, output: str) -> None:
|
|
132
|
+
type_map = _build_map_all(build, python=True)
|
|
133
|
+
|
|
134
|
+
stripped = _dict_null_strip(asdict_for_yaml_dump(type_map))
|
|
135
|
+
|
|
136
|
+
yaml_content = yaml.dump(stripped, default_flow_style=False, sort_keys=True)
|
|
137
|
+
util.rewrite_file(f"{output}/type_map.yaml", yaml_content)
|
|
138
|
+
|
|
139
|
+
|
|
98
140
|
@dataclasses.dataclass
|
|
99
141
|
class MapProperty:
|
|
100
142
|
api_name: str
|
|
@@ -106,7 +148,7 @@ class MapProperty:
|
|
|
106
148
|
desc: str | None
|
|
107
149
|
# We don't have typing on defaults yet, relying on emitters to check it. Limit
|
|
108
150
|
# use of this field, as it'll necessarily change when adding type info
|
|
109
|
-
default:
|
|
151
|
+
default: PureJsonValue
|
|
110
152
|
|
|
111
153
|
|
|
112
154
|
@dataclasses.dataclass
|
|
@@ -129,12 +171,19 @@ class MapTypeAlias(MapTypeBase):
|
|
|
129
171
|
discriminator: str | None
|
|
130
172
|
|
|
131
173
|
|
|
174
|
+
@dataclasses.dataclass
|
|
175
|
+
class StringEnumValue:
|
|
176
|
+
value: str
|
|
177
|
+
label: str
|
|
178
|
+
deprecated: bool = False
|
|
179
|
+
|
|
180
|
+
|
|
132
181
|
@dataclasses.dataclass
|
|
133
182
|
class MapStringEnum(MapTypeBase):
|
|
134
|
-
values: dict[str,
|
|
183
|
+
values: dict[str, StringEnumValue]
|
|
135
184
|
|
|
136
185
|
|
|
137
|
-
MapType
|
|
186
|
+
MapType = MapTypeObject | MapTypeAlias | MapStringEnum
|
|
138
187
|
|
|
139
188
|
|
|
140
189
|
@dataclasses.dataclass
|
|
@@ -147,11 +196,14 @@ class MapAll:
|
|
|
147
196
|
namespaces: dict[str, MapNamespace]
|
|
148
197
|
|
|
149
198
|
|
|
150
|
-
def _build_map_all(build: builder.SpecBuilder) -> MapAll:
|
|
199
|
+
def _build_map_all(build: builder.SpecBuilder, *, python: bool = False) -> MapAll:
|
|
151
200
|
map_all = MapAll(namespaces={})
|
|
152
201
|
|
|
153
202
|
for namespace in build.namespaces.values():
|
|
154
|
-
if not namespace.emit_type_info:
|
|
203
|
+
if not python and not namespace.emit_type_info:
|
|
204
|
+
continue
|
|
205
|
+
|
|
206
|
+
if python and not namespace.emit_type_info_python:
|
|
155
207
|
continue
|
|
156
208
|
|
|
157
209
|
map_namespace = MapNamespace(types={})
|
|
@@ -172,9 +224,9 @@ class InheritablePropertyParts:
|
|
|
172
224
|
at that level, but that needs to be done in builder. When that is done, the
|
|
173
225
|
"label" and "desc" could probably be removed from this list."""
|
|
174
226
|
|
|
175
|
-
label:
|
|
176
|
-
desc:
|
|
177
|
-
ext_info:
|
|
227
|
+
label: str | None = None
|
|
228
|
+
desc: str | None = None
|
|
229
|
+
ext_info: type_info_t.ExtInfo | None = None
|
|
178
230
|
|
|
179
231
|
|
|
180
232
|
def _extract_inheritable_property_parts(
|
|
@@ -201,8 +253,13 @@ def _extract_inheritable_property_parts(
|
|
|
201
253
|
elif base_parts.ext_info is None:
|
|
202
254
|
ext_info = local_ext_info
|
|
203
255
|
else:
|
|
204
|
-
ext_info =
|
|
205
|
-
|
|
256
|
+
ext_info = dataclasses.replace(
|
|
257
|
+
local_ext_info,
|
|
258
|
+
**{
|
|
259
|
+
field.name: getattr(base_parts.ext_info, field.name)
|
|
260
|
+
for field in dataclasses.fields(type_info_t.ExtInfo)
|
|
261
|
+
if getattr(base_parts.ext_info, field.name) is not None
|
|
262
|
+
},
|
|
206
263
|
)
|
|
207
264
|
|
|
208
265
|
return InheritablePropertyParts(label=label, desc=desc, ext_info=ext_info)
|
|
@@ -214,7 +271,7 @@ ALL_FIELDS_GROUP = "*all_fields"
|
|
|
214
271
|
|
|
215
272
|
def _extract_and_validate_layout(
|
|
216
273
|
stype: builder.SpecTypeDefnObject,
|
|
217
|
-
ext_info:
|
|
274
|
+
ext_info: type_info_t.ExtInfo,
|
|
218
275
|
base_layout: ExtInfoLayout | None,
|
|
219
276
|
) -> ExtInfoLayout:
|
|
220
277
|
"""
|
|
@@ -230,13 +287,15 @@ def _extract_and_validate_layout(
|
|
|
230
287
|
for group in ext_info.layout.groups:
|
|
231
288
|
fields = set(group.fields or [])
|
|
232
289
|
for field in fields:
|
|
233
|
-
assert field in stype.properties,
|
|
290
|
+
assert field in stype.properties or field == DISCRIMINATOR_COMMON_NAME, (
|
|
291
|
+
f"layout-refers-to-missing-field:{field}"
|
|
292
|
+
)
|
|
234
293
|
|
|
235
294
|
local_ref_name = None
|
|
236
295
|
if group.ref_name is not None:
|
|
237
|
-
assert (
|
|
238
|
-
|
|
239
|
-
)
|
|
296
|
+
assert base_layout is None or base_layout.get(group.ref_name) is None, (
|
|
297
|
+
f"group-name-duplicate-in-base:{group.ref_name}"
|
|
298
|
+
)
|
|
240
299
|
local_ref_name = group.ref_name
|
|
241
300
|
|
|
242
301
|
if group.extends:
|
|
@@ -255,14 +314,34 @@ def _extract_and_validate_layout(
|
|
|
255
314
|
assert group_ref_name in layout, f"missing-base-group:{group_ref_name}"
|
|
256
315
|
|
|
257
316
|
for prop_ref_name in stype.properties:
|
|
258
|
-
assert prop_ref_name in all_fields_group,
|
|
317
|
+
assert prop_ref_name in all_fields_group, (
|
|
318
|
+
f"layout-missing-field:{prop_ref_name}"
|
|
319
|
+
)
|
|
259
320
|
|
|
260
321
|
return layout
|
|
261
322
|
|
|
262
323
|
|
|
324
|
+
def _pull_property_from_type_recursively(
|
|
325
|
+
stype: builder.SpecTypeDefnObject,
|
|
326
|
+
property_name: str,
|
|
327
|
+
) -> builder.SpecProperty | None:
|
|
328
|
+
assert stype.properties is not None
|
|
329
|
+
prop = stype.properties.get(property_name)
|
|
330
|
+
if prop is not None:
|
|
331
|
+
return prop
|
|
332
|
+
|
|
333
|
+
if stype.base is None:
|
|
334
|
+
return None
|
|
335
|
+
|
|
336
|
+
return _pull_property_from_type_recursively(stype.base, property_name)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
DISCRIMINATOR_COMMON_NAME = "type"
|
|
340
|
+
|
|
341
|
+
|
|
263
342
|
def _validate_type_ext_info(
|
|
264
343
|
stype: builder.SpecTypeDefnObject,
|
|
265
|
-
) -> tuple[ExtInfoLayout | None,
|
|
344
|
+
) -> tuple[ExtInfoLayout | None, type_info_t.ExtInfo | None]:
|
|
266
345
|
ext_info = _parse_ext_info(stype.ext_info)
|
|
267
346
|
if ext_info is None:
|
|
268
347
|
return None, None
|
|
@@ -270,9 +349,19 @@ def _validate_type_ext_info(
|
|
|
270
349
|
if ext_info.label_fields is not None:
|
|
271
350
|
assert stype.properties is not None
|
|
272
351
|
for name in ext_info.label_fields:
|
|
273
|
-
|
|
352
|
+
if name == DISCRIMINATOR_COMMON_NAME:
|
|
353
|
+
continue
|
|
354
|
+
prop = _pull_property_from_type_recursively(stype, name)
|
|
274
355
|
assert prop is not None, f"missing-label-field:{name}"
|
|
275
356
|
|
|
357
|
+
if ext_info.actions is not None:
|
|
358
|
+
assert stype.properties is not None
|
|
359
|
+
for action in ext_info.actions:
|
|
360
|
+
if action.property == DISCRIMINATOR_COMMON_NAME:
|
|
361
|
+
continue
|
|
362
|
+
prop = _pull_property_from_type_recursively(stype, action.property)
|
|
363
|
+
assert prop is not None, f"missing-action-field:{action.property}"
|
|
364
|
+
|
|
276
365
|
if not stype.is_base and isinstance(stype.base, builder.SpecTypeDefnObject):
|
|
277
366
|
base_layout, _ = _validate_type_ext_info(stype.base)
|
|
278
367
|
else:
|
|
@@ -354,7 +443,11 @@ def _build_map_type(
|
|
|
354
443
|
# IMPROVE: We probably want the label here, but this requires a change
|
|
355
444
|
# to the front-end type-info and form code to handle
|
|
356
445
|
values={
|
|
357
|
-
entry.value: (
|
|
446
|
+
entry.value: StringEnumValue(
|
|
447
|
+
value=entry.value,
|
|
448
|
+
label=entry.label or entry.name,
|
|
449
|
+
deprecated=entry.deprecated,
|
|
450
|
+
)
|
|
358
451
|
for entry in stype.values.values()
|
|
359
452
|
},
|
|
360
453
|
)
|
|
@@ -362,7 +455,7 @@ def _build_map_type(
|
|
|
362
455
|
return None
|
|
363
456
|
|
|
364
457
|
|
|
365
|
-
def _parse_ext_info(in_ext: Any) ->
|
|
458
|
+
def _parse_ext_info(in_ext: Any) -> type_info_t.ExtInfo | None:
|
|
366
459
|
if in_ext is None:
|
|
367
460
|
return None
|
|
368
461
|
assert isinstance(in_ext, dict)
|
|
@@ -380,10 +473,12 @@ def _parse_ext_info(in_ext: Any) -> Optional[data_t.ExtInfo]:
|
|
|
380
473
|
df["result_type"] = serialize_for_storage(converted)
|
|
381
474
|
mod_ext["data_format"] = df
|
|
382
475
|
|
|
476
|
+
if "open_api" in mod_ext:
|
|
477
|
+
del mod_ext["open_api"]
|
|
383
478
|
return ext_info_parser.parse_storage(mod_ext)
|
|
384
479
|
|
|
385
480
|
|
|
386
|
-
def _convert_ext_info(in_ext: Any) ->
|
|
481
|
+
def _convert_ext_info(in_ext: Any) -> PureJsonValue | None:
|
|
387
482
|
# we need to convert this to API storage since it'll be used as-is in the UI
|
|
388
483
|
parsed = _parse_ext_info(in_ext)
|
|
389
484
|
return cast(PureJsonValue, serialize_for_api(parsed))
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import re
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from io import StringIO
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import assert_never
|
|
7
|
+
|
|
8
|
+
from main.base.types import (
|
|
9
|
+
base_t,
|
|
10
|
+
ui_entry_actions_t,
|
|
11
|
+
)
|
|
12
|
+
from pkgs.serialization_util import serialize_for_api
|
|
13
|
+
from pkgs.type_spec import emit_typescript_util
|
|
14
|
+
from pkgs.type_spec.builder import (
|
|
15
|
+
BaseTypeName,
|
|
16
|
+
NameCase,
|
|
17
|
+
RawDict,
|
|
18
|
+
SpecBuilder,
|
|
19
|
+
SpecNamespace,
|
|
20
|
+
SpecTypeDefnObject,
|
|
21
|
+
)
|
|
22
|
+
from pkgs.type_spec.config import Config
|
|
23
|
+
from pkgs.type_spec.load_types import load_types
|
|
24
|
+
from pkgs.type_spec.util import rewrite_file
|
|
25
|
+
from pkgs.type_spec.value_spec.convert_type import convert_from_value_spec_type
|
|
26
|
+
|
|
27
|
+
_INIT_ACTION_INDEX_TYPE_DATA = {
|
|
28
|
+
"EntryActionInfo<InputT, OutputT>": {
|
|
29
|
+
"type": BaseTypeName.s_object,
|
|
30
|
+
"properties": {"inputs": {"type": "InputT"}, "outputs": {"type": "OutputT"}},
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
_TYPES_ROOT = "unc_types"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass(kw_only=True)
|
|
37
|
+
class EntryActionTypeInfo:
|
|
38
|
+
inputs_type: SpecTypeDefnObject
|
|
39
|
+
outputs_type: SpecTypeDefnObject
|
|
40
|
+
name: str
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def ui_entry_variable_to_type_spec_type(
|
|
44
|
+
variable: ui_entry_actions_t.UiEntryActionVariable,
|
|
45
|
+
) -> str:
|
|
46
|
+
match variable:
|
|
47
|
+
case ui_entry_actions_t.UiEntryActionVariableString():
|
|
48
|
+
return BaseTypeName.s_string
|
|
49
|
+
case ui_entry_actions_t.UiEntryActionVariableSingleEntity():
|
|
50
|
+
return "ObjectId"
|
|
51
|
+
case _:
|
|
52
|
+
assert_never(variable)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def construct_inputs_type_data(
|
|
56
|
+
vars: dict[str, ui_entry_actions_t.UiEntryActionVariable],
|
|
57
|
+
) -> RawDict:
|
|
58
|
+
if len(vars) == 0:
|
|
59
|
+
return {"type": BaseTypeName.s_object}
|
|
60
|
+
properties: dict[str, dict[str, str]] = {}
|
|
61
|
+
for input_name, input_defn in (vars).items():
|
|
62
|
+
properties[f"{input_name}"] = {
|
|
63
|
+
"type": ui_entry_variable_to_type_spec_type(input_defn)
|
|
64
|
+
}
|
|
65
|
+
return {"type": BaseTypeName.s_object, "properties": properties}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def construct_outputs_type_data(
|
|
69
|
+
vars: dict[str, ui_entry_actions_t.UiEntryActionOutput],
|
|
70
|
+
) -> RawDict:
|
|
71
|
+
if len(vars) == 0:
|
|
72
|
+
return {"type": BaseTypeName.s_object}
|
|
73
|
+
properties: dict[str, dict[str, str]] = {}
|
|
74
|
+
for output_name, output_defn in (vars).items():
|
|
75
|
+
# All outputs are optional
|
|
76
|
+
properties[f"{output_name}"] = {
|
|
77
|
+
"type": f"Optional<{convert_from_value_spec_type(output_defn.vs_type)}>"
|
|
78
|
+
}
|
|
79
|
+
return {"type": BaseTypeName.s_object, "properties": properties}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def construct_outputs_type(
|
|
83
|
+
*,
|
|
84
|
+
action_scope: ui_entry_actions_t.ActionScope,
|
|
85
|
+
vars: dict[str, ui_entry_actions_t.UiEntryActionOutput],
|
|
86
|
+
builder: SpecBuilder,
|
|
87
|
+
namespace: SpecNamespace,
|
|
88
|
+
) -> SpecTypeDefnObject:
|
|
89
|
+
stype = SpecTypeDefnObject(
|
|
90
|
+
namespace=namespace,
|
|
91
|
+
name=emit_typescript_util.ts_type_name(f"{action_scope}_outputs"),
|
|
92
|
+
)
|
|
93
|
+
namespace.types[stype.name] = stype
|
|
94
|
+
stype.process(
|
|
95
|
+
builder=builder,
|
|
96
|
+
data=construct_outputs_type_data(vars=vars),
|
|
97
|
+
)
|
|
98
|
+
return stype
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def construct_inputs_type(
|
|
102
|
+
*,
|
|
103
|
+
action_scope: ui_entry_actions_t.ActionScope,
|
|
104
|
+
vars: dict[str, ui_entry_actions_t.UiEntryActionVariable],
|
|
105
|
+
builder: SpecBuilder,
|
|
106
|
+
namespace: SpecNamespace,
|
|
107
|
+
) -> SpecTypeDefnObject:
|
|
108
|
+
stype = SpecTypeDefnObject(
|
|
109
|
+
namespace=namespace,
|
|
110
|
+
name=emit_typescript_util.ts_type_name(f"{action_scope}_inputs"),
|
|
111
|
+
)
|
|
112
|
+
stype.process(builder=builder, data=construct_inputs_type_data(vars))
|
|
113
|
+
namespace.types[stype.name] = stype
|
|
114
|
+
return stype
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _get_types_root(destination_root: Path) -> Path:
|
|
118
|
+
return destination_root / "types"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def emit_imports_ts(
|
|
122
|
+
namespaces: set[SpecNamespace],
|
|
123
|
+
out: StringIO,
|
|
124
|
+
) -> None:
|
|
125
|
+
for ns in sorted(
|
|
126
|
+
namespaces,
|
|
127
|
+
key=lambda ns: ns.name,
|
|
128
|
+
):
|
|
129
|
+
import_as = emit_typescript_util.resolve_namespace_ref(ns)
|
|
130
|
+
import_from = f"{_TYPES_ROOT}/{ns.name}"
|
|
131
|
+
out.write(f'import * as {import_as} from "{import_from}"\n')
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def emit_entry_action_definition(
|
|
135
|
+
*,
|
|
136
|
+
ctx: emit_typescript_util.EmitTypescriptContext,
|
|
137
|
+
defn: ui_entry_actions_t.UiEntryActionDefinition,
|
|
138
|
+
builder: SpecBuilder,
|
|
139
|
+
action_scope: ui_entry_actions_t.ActionScope,
|
|
140
|
+
) -> EntryActionTypeInfo:
|
|
141
|
+
inputs_type = construct_inputs_type(
|
|
142
|
+
action_scope=action_scope,
|
|
143
|
+
vars=defn.inputs,
|
|
144
|
+
builder=builder,
|
|
145
|
+
namespace=ctx.namespace,
|
|
146
|
+
)
|
|
147
|
+
outputs_type = construct_outputs_type(
|
|
148
|
+
action_scope=action_scope,
|
|
149
|
+
vars=defn.outputs,
|
|
150
|
+
builder=builder,
|
|
151
|
+
namespace=ctx.namespace,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return EntryActionTypeInfo(
|
|
155
|
+
inputs_type=inputs_type,
|
|
156
|
+
outputs_type=outputs_type,
|
|
157
|
+
name=action_scope,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _validate_input(input: ui_entry_actions_t.UiEntryActionVariable) -> None:
|
|
162
|
+
if "_" in input.vs_var_name:
|
|
163
|
+
raise ValueError(f"Expected camelCase for variable {input.vs_var_name}")
|
|
164
|
+
if not re.fullmatch(base_t.REF_NAME_STRICT_REGEX, input.vs_var_name):
|
|
165
|
+
raise ValueError(
|
|
166
|
+
f"Variable {input.vs_var_name} has invalid syntax. See REF_NAME_STRICT_REGEX"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def emit_query_index(
|
|
171
|
+
ctx: emit_typescript_util.EmitTypescriptContext,
|
|
172
|
+
defn_infos: list[EntryActionTypeInfo],
|
|
173
|
+
index_path: Path,
|
|
174
|
+
builder: SpecBuilder,
|
|
175
|
+
definitions: dict[
|
|
176
|
+
ui_entry_actions_t.ActionScope, ui_entry_actions_t.UiEntryActionDefinition
|
|
177
|
+
],
|
|
178
|
+
) -> bool:
|
|
179
|
+
query_index_type_data = {
|
|
180
|
+
**_INIT_ACTION_INDEX_TYPE_DATA,
|
|
181
|
+
"EntityActionTypeLookup": {
|
|
182
|
+
"type": BaseTypeName.s_object,
|
|
183
|
+
"properties": {
|
|
184
|
+
defn_info.name: {
|
|
185
|
+
"type": f"EntryActionInfo<{defn_info.inputs_type.name},{defn_info.outputs_type.name}>",
|
|
186
|
+
"name_case": NameCase.preserve,
|
|
187
|
+
}
|
|
188
|
+
for defn_info in defn_infos
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
"InputInfo": {
|
|
192
|
+
"type": BaseTypeName.s_object,
|
|
193
|
+
"properties": {
|
|
194
|
+
"value_spec_var": {"type": "String"},
|
|
195
|
+
"type": {"type": "ui_entry_actions.UiEntryActionDataType"},
|
|
196
|
+
"variable": {"type": "ui_entry_actions.UiEntryActionVariable"},
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
"OutputInfo": {
|
|
200
|
+
"type": BaseTypeName.s_object,
|
|
201
|
+
"properties": {
|
|
202
|
+
"name": {"type": "String"},
|
|
203
|
+
"desc": {"type": "String"},
|
|
204
|
+
"type": {"type": "value_spec.BaseType"},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
"DefinitionInfo": {
|
|
208
|
+
"type": BaseTypeName.s_object,
|
|
209
|
+
"properties": {
|
|
210
|
+
"inputs": {
|
|
211
|
+
"type": "ReadonlyArray<InputInfo>",
|
|
212
|
+
},
|
|
213
|
+
"outputs": {
|
|
214
|
+
"type": "ReadonlyArray<OutputInfo>",
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
}
|
|
219
|
+
ctx.namespace.prescan(query_index_type_data)
|
|
220
|
+
ctx.namespace.process(
|
|
221
|
+
builder=builder,
|
|
222
|
+
data=query_index_type_data,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
defn_lookup_info = {}
|
|
226
|
+
for scope, defn in definitions.items():
|
|
227
|
+
inputs = []
|
|
228
|
+
outputs = []
|
|
229
|
+
for input in defn.inputs.values():
|
|
230
|
+
_validate_input(input)
|
|
231
|
+
inputs.append(
|
|
232
|
+
serialize_for_api({
|
|
233
|
+
"value_spec_var": input.vs_var_name,
|
|
234
|
+
"type": input.type,
|
|
235
|
+
"variable": input,
|
|
236
|
+
})
|
|
237
|
+
)
|
|
238
|
+
for name, output in defn.outputs.items():
|
|
239
|
+
outputs.append(
|
|
240
|
+
serialize_for_api({
|
|
241
|
+
"name": name,
|
|
242
|
+
"desc": output.description,
|
|
243
|
+
"type": output.vs_type,
|
|
244
|
+
})
|
|
245
|
+
)
|
|
246
|
+
defn_lookup_info[scope] = {"inputs": inputs, "outputs": outputs}
|
|
247
|
+
|
|
248
|
+
defn_lookup_out = f"export const DEFINITION_LOOKUP = {json.dumps(defn_lookup_info, sort_keys=True, indent=2)} as const\n\nexport const DEFINITION_LOOKUP_TYPED = DEFINITION_LOOKUP as Record<UiEntryActionsT.ActionScope, DefinitionInfo>\n"
|
|
249
|
+
|
|
250
|
+
for stype in ctx.namespace.types.values():
|
|
251
|
+
emit_typescript_util.emit_type_ts(
|
|
252
|
+
ctx=ctx,
|
|
253
|
+
stype=stype,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
import_buffer = StringIO()
|
|
257
|
+
emit_typescript_util.emit_namespace_imports_from_root_ts(
|
|
258
|
+
namespaces=ctx.namespaces,
|
|
259
|
+
out=import_buffer,
|
|
260
|
+
root=_TYPES_ROOT,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
return rewrite_file(
|
|
264
|
+
content=import_buffer.getvalue() + ctx.out.getvalue() + defn_lookup_out,
|
|
265
|
+
filename=str(index_path),
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def generate_entry_actions_typescript(
|
|
270
|
+
*,
|
|
271
|
+
definitions: dict[
|
|
272
|
+
ui_entry_actions_t.ActionScope, ui_entry_actions_t.UiEntryActionDefinition
|
|
273
|
+
],
|
|
274
|
+
destination_root: Path,
|
|
275
|
+
materials_type_spec_config: Config,
|
|
276
|
+
) -> None:
|
|
277
|
+
builder = load_types(materials_type_spec_config)
|
|
278
|
+
assert builder is not None
|
|
279
|
+
|
|
280
|
+
definition_buffer = StringIO()
|
|
281
|
+
index_namespace = SpecNamespace(name="index")
|
|
282
|
+
ctx = emit_typescript_util.EmitTypescriptContext(
|
|
283
|
+
out=definition_buffer,
|
|
284
|
+
namespace=index_namespace,
|
|
285
|
+
api_endpoints={},
|
|
286
|
+
)
|
|
287
|
+
builder.namespaces[index_namespace.name] = index_namespace
|
|
288
|
+
|
|
289
|
+
defn_infos: list[EntryActionTypeInfo] = []
|
|
290
|
+
|
|
291
|
+
for action_scope, defn in definitions.items():
|
|
292
|
+
defn_infos.append(
|
|
293
|
+
emit_entry_action_definition(
|
|
294
|
+
action_scope=action_scope,
|
|
295
|
+
ctx=ctx,
|
|
296
|
+
defn=defn,
|
|
297
|
+
builder=builder,
|
|
298
|
+
)
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
index_path = _get_types_root(destination_root) / "index.ts"
|
|
302
|
+
emit_query_index(
|
|
303
|
+
ctx=ctx,
|
|
304
|
+
builder=builder,
|
|
305
|
+
defn_infos=defn_infos,
|
|
306
|
+
definitions=definitions,
|
|
307
|
+
index_path=index_path,
|
|
308
|
+
)
|
pkgs/type_spec/util.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import os
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import TypeVar, Union
|
|
5
5
|
|
|
6
6
|
import regex as re
|
|
7
7
|
|
|
@@ -29,8 +29,8 @@ LiteralTypeValue = Union[str, bool]
|
|
|
29
29
|
class ParsedTypePart:
|
|
30
30
|
name: str
|
|
31
31
|
# An empty list is distinct from None
|
|
32
|
-
parameters:
|
|
33
|
-
literal_value:
|
|
32
|
+
parameters: list["ParsedTypePath"] | None = None
|
|
33
|
+
literal_value: LiteralTypeValue | None = None
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
ParsedTypePath = list[ParsedTypePart]
|
|
@@ -159,7 +159,7 @@ def is_valid_property_name(name: str) -> bool:
|
|
|
159
159
|
def check_fields(data: dict[str, T], allowed: list[str]) -> None:
|
|
160
160
|
for key in data:
|
|
161
161
|
if key not in allowed:
|
|
162
|
-
raise Exception(f"unexpected-field: {key}")
|
|
162
|
+
raise Exception(f"unexpected-field: {key}. Allowed: {allowed}")
|
|
163
163
|
|
|
164
164
|
|
|
165
165
|
def split_any_name(name: str) -> list[str]:
|