UncountablePythonSDK 0.0.8__py3-none-any.whl → 0.0.92__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.
- UncountablePythonSDK-0.0.92.dist-info/METADATA +61 -0
- UncountablePythonSDK-0.0.92.dist-info/RECORD +301 -0
- {UncountablePythonSDK-0.0.8.dist-info → UncountablePythonSDK-0.0.92.dist-info}/WHEEL +1 -1
- {UncountablePythonSDK-0.0.8.dist-info → UncountablePythonSDK-0.0.92.dist-info}/top_level.txt +1 -1
- docs/.gitignore +1 -0
- docs/conf.py +57 -0
- docs/index.md +13 -0
- docs/justfile +12 -0
- docs/quickstart.md +19 -0
- docs/requirements.txt +7 -0
- docs/static/favicons/android-chrome-192x192.png +0 -0
- docs/static/favicons/android-chrome-512x512.png +0 -0
- docs/static/favicons/apple-touch-icon.png +0 -0
- docs/static/favicons/browserconfig.xml +9 -0
- docs/static/favicons/favicon-16x16.png +0 -0
- docs/static/favicons/favicon-32x32.png +0 -0
- docs/static/favicons/manifest.json +18 -0
- docs/static/favicons/mstile-150x150.png +0 -0
- docs/static/favicons/safari-pinned-tab.svg +32 -0
- docs/static/logo_blue.png +0 -0
- examples/async_batch.py +35 -0
- examples/create_entity.py +22 -17
- examples/download_files.py +26 -0
- examples/edit_recipe_inputs.py +50 -0
- examples/integration-server/jobs/materials_auto/example_cron.py +18 -0
- examples/integration-server/jobs/materials_auto/example_wh.py +15 -0
- examples/integration-server/jobs/materials_auto/profile.yaml +43 -0
- examples/integration-server/pyproject.toml +224 -0
- examples/invoke_uploader.py +26 -0
- examples/set_recipe_metadata_file.py +40 -0
- examples/set_recipe_output_file_sdk.py +26 -0
- examples/upload_files.py +18 -0
- pkgs/argument_parser/__init__.py +5 -0
- pkgs/argument_parser/_is_enum.py +1 -6
- pkgs/argument_parser/argument_parser.py +232 -76
- pkgs/argument_parser/case_convert.py +4 -3
- pkgs/filesystem_utils/__init__.py +20 -0
- pkgs/filesystem_utils/_blob_session.py +137 -0
- pkgs/filesystem_utils/_gdrive_session.py +309 -0
- pkgs/filesystem_utils/_local_session.py +69 -0
- pkgs/filesystem_utils/_s3_session.py +117 -0
- pkgs/filesystem_utils/_sftp_session.py +147 -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 +65 -50
- 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/_get_type_for_serialization.py +1 -3
- pkgs/serialization_util/convert_to_snakecase.py +27 -0
- pkgs/serialization_util/dataclasses.py +14 -0
- pkgs/serialization_util/serialization_helpers.py +116 -74
- pkgs/strenum_compat/strenum_compat.py +1 -9
- pkgs/type_spec/actions_registry/__init__.py +0 -0
- pkgs/type_spec/actions_registry/__main__.py +126 -0
- pkgs/type_spec/actions_registry/emit_typescript.py +182 -0
- pkgs/type_spec/builder.py +475 -89
- pkgs/type_spec/config.py +24 -19
- pkgs/type_spec/emit_io_ts.py +5 -2
- pkgs/type_spec/emit_open_api.py +266 -32
- pkgs/type_spec/emit_open_api_util.py +32 -13
- pkgs/type_spec/emit_python.py +599 -151
- pkgs/type_spec/emit_typescript.py +74 -273
- pkgs/type_spec/emit_typescript_util.py +239 -5
- pkgs/type_spec/load_types.py +55 -10
- pkgs/type_spec/open_api_util.py +30 -41
- pkgs/type_spec/parts/base.py.prepart +4 -3
- pkgs/type_spec/type_info/emit_type_info.py +178 -16
- pkgs/type_spec/util.py +11 -11
- pkgs/type_spec/value_spec/__main__.py +3 -3
- pkgs/type_spec/value_spec/convert_type.py +8 -1
- pkgs/type_spec/value_spec/emit_python.py +13 -4
- uncountable/__init__.py +1 -2
- uncountable/core/__init__.py +12 -2
- uncountable/core/async_batch.py +37 -0
- uncountable/core/client.py +293 -43
- uncountable/core/environment.py +41 -0
- uncountable/core/file_upload.py +135 -0
- uncountable/core/types.py +17 -0
- uncountable/integration/__init__.py +0 -0
- uncountable/integration/cli.py +49 -0
- uncountable/integration/construct_client.py +51 -0
- uncountable/integration/cron.py +29 -0
- uncountable/integration/db/__init__.py +0 -0
- uncountable/integration/db/connect.py +18 -0
- uncountable/integration/db/session.py +25 -0
- uncountable/integration/entrypoint.py +13 -0
- uncountable/integration/executors/__init__.py +0 -0
- uncountable/integration/executors/executors.py +148 -0
- uncountable/integration/executors/generic_upload_executor.py +284 -0
- uncountable/integration/executors/script_executor.py +25 -0
- uncountable/integration/job.py +87 -0
- uncountable/integration/queue_runner/__init__.py +0 -0
- uncountable/integration/queue_runner/command_server/__init__.py +24 -0
- uncountable/integration/queue_runner/command_server/command_client.py +68 -0
- uncountable/integration/queue_runner/command_server/command_server.py +64 -0
- uncountable/integration/queue_runner/command_server/protocol/__init__.py +0 -0
- uncountable/integration/queue_runner/command_server/protocol/command_server.proto +22 -0
- uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.py +40 -0
- uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.pyi +38 -0
- uncountable/integration/queue_runner/command_server/protocol/command_server_pb2_grpc.py +129 -0
- uncountable/integration/queue_runner/command_server/types.py +52 -0
- uncountable/integration/queue_runner/datastore/__init__.py +3 -0
- uncountable/integration/queue_runner/datastore/datastore_sqlite.py +93 -0
- uncountable/integration/queue_runner/datastore/interface.py +19 -0
- uncountable/integration/queue_runner/datastore/model.py +17 -0
- uncountable/integration/queue_runner/job_scheduler.py +163 -0
- uncountable/integration/queue_runner/queue_runner.py +26 -0
- uncountable/integration/queue_runner/types.py +7 -0
- uncountable/integration/queue_runner/worker.py +119 -0
- uncountable/integration/scan_profiles.py +67 -0
- uncountable/integration/scheduler.py +150 -0
- uncountable/integration/secret_retrieval/__init__.py +3 -0
- uncountable/integration/secret_retrieval/retrieve_secret.py +93 -0
- uncountable/integration/server.py +117 -0
- uncountable/integration/telemetry.py +209 -0
- uncountable/integration/webhook_server/entrypoint.py +170 -0
- uncountable/types/__init__.py +136 -20
- uncountable/types/api/batch/execute_batch.py +15 -7
- uncountable/types/api/batch/execute_batch_load_async.py +42 -0
- uncountable/types/api/chemical/__init__.py +1 -0
- uncountable/types/api/chemical/convert_chemical_formats.py +63 -0
- uncountable/types/api/entity/create_entities.py +23 -11
- uncountable/types/api/entity/create_entity.py +21 -12
- uncountable/types/api/entity/get_entities_data.py +18 -8
- uncountable/types/api/entity/grant_entity_permissions.py +48 -0
- uncountable/types/api/entity/list_entities.py +27 -12
- uncountable/types/api/entity/lock_entity.py +45 -0
- uncountable/types/api/entity/resolve_entity_ids.py +17 -7
- uncountable/types/api/entity/set_entity_field_values.py +44 -0
- uncountable/types/api/entity/set_values.py +14 -7
- uncountable/types/api/entity/transition_entity_phase.py +80 -0
- 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 +44 -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/__init__.py +1 -0
- uncountable/types/api/id_source/list_id_source.py +56 -0
- uncountable/types/api/id_source/match_id_source.py +54 -0
- uncountable/types/api/input_groups/get_input_group_names.py +16 -6
- uncountable/types/api/inputs/create_inputs.py +24 -11
- uncountable/types/api/inputs/get_input_data.py +32 -13
- uncountable/types/api/inputs/get_input_names.py +18 -8
- uncountable/types/api/inputs/get_inputs_data.py +29 -10
- uncountable/types/api/inputs/set_input_attribute_values.py +16 -9
- 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/material_families/__init__.py +1 -0
- uncountable/types/api/material_families/update_entity_material_families.py +48 -0
- uncountable/types/api/outputs/get_output_data.py +32 -16
- uncountable/types/api/outputs/get_output_names.py +18 -8
- uncountable/types/api/outputs/resolve_output_conditions.py +23 -10
- uncountable/types/api/permissions/__init__.py +1 -0
- uncountable/types/api/permissions/set_core_permissions.py +105 -0
- uncountable/types/api/project/get_projects.py +17 -7
- uncountable/types/api/project/get_projects_data.py +21 -11
- uncountable/types/api/recipe_links/__init__.py +1 -0
- uncountable/types/api/recipe_links/create_recipe_link.py +46 -0
- uncountable/types/api/recipe_links/remove_recipe_link.py +45 -0
- uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +18 -8
- uncountable/types/api/recipes/add_recipe_to_project.py +42 -0
- uncountable/types/api/recipes/archive_recipes.py +42 -0
- uncountable/types/api/recipes/associate_recipe_as_input.py +44 -0
- uncountable/types/api/recipes/associate_recipe_as_lot.py +43 -0
- uncountable/types/api/recipes/clear_recipe_outputs.py +42 -0
- uncountable/types/api/recipes/create_recipe.py +51 -0
- uncountable/types/api/recipes/create_recipes.py +25 -12
- uncountable/types/api/recipes/disassociate_recipe_as_input.py +42 -0
- uncountable/types/api/recipes/edit_recipe_inputs.py +283 -0
- uncountable/types/api/recipes/get_column_calculation_values.py +58 -0
- uncountable/types/api/recipes/get_curve.py +15 -7
- uncountable/types/api/recipes/get_recipe_calculations.py +17 -10
- uncountable/types/api/recipes/get_recipe_links.py +13 -6
- uncountable/types/api/recipes/get_recipe_names.py +16 -6
- uncountable/types/api/recipes/get_recipe_output_metadata.py +14 -7
- uncountable/types/api/recipes/get_recipes_data.py +63 -38
- uncountable/types/api/recipes/lock_recipes.py +63 -0
- uncountable/types/api/recipes/remove_recipe_from_project.py +42 -0
- uncountable/types/api/recipes/set_recipe_inputs.py +19 -10
- uncountable/types/api/recipes/set_recipe_metadata.py +43 -0
- uncountable/types/api/recipes/set_recipe_output_annotations.py +115 -0
- uncountable/types/api/recipes/set_recipe_output_file.py +56 -0
- uncountable/types/api/recipes/set_recipe_outputs.py +26 -12
- uncountable/types/api/recipes/set_recipe_tags.py +109 -0
- uncountable/types/api/recipes/unarchive_recipes.py +41 -0
- uncountable/types/api/recipes/unlock_recipes.py +50 -0
- uncountable/types/api/triggers/__init__.py +1 -0
- uncountable/types/api/triggers/run_trigger.py +43 -0
- uncountable/types/api/uploader/__init__.py +1 -0
- uncountable/types/api/uploader/invoke_uploader.py +47 -0
- uncountable/types/async_batch.py +13 -0
- uncountable/types/async_batch_processor.py +384 -0
- uncountable/types/async_batch_t.py +97 -0
- uncountable/types/async_jobs.py +9 -0
- uncountable/types/async_jobs_t.py +53 -0
- uncountable/types/auth_retrieval.py +12 -0
- uncountable/types/auth_retrieval_t.py +75 -0
- uncountable/types/base.py +5 -78
- uncountable/types/base_t.py +85 -0
- uncountable/types/calculations.py +3 -18
- uncountable/types/calculations_t.py +27 -0
- uncountable/types/chemical_structure.py +8 -0
- uncountable/types/chemical_structure_t.py +28 -0
- uncountable/types/client_base.py +1093 -54
- uncountable/types/client_config.py +8 -0
- uncountable/types/client_config_t.py +26 -0
- uncountable/types/curves.py +5 -42
- uncountable/types/curves_t.py +51 -0
- uncountable/types/entity.py +8 -269
- uncountable/types/entity_t.py +393 -0
- uncountable/types/experiment_groups.py +3 -18
- uncountable/types/experiment_groups_t.py +27 -0
- uncountable/types/field_values.py +17 -60
- uncountable/types/field_values_t.py +204 -0
- uncountable/types/fields.py +3 -19
- uncountable/types/fields_t.py +28 -0
- uncountable/types/generic_upload.py +15 -0
- uncountable/types/generic_upload_t.py +119 -0
- uncountable/types/id_source.py +12 -0
- uncountable/types/id_source_t.py +68 -0
- uncountable/types/identifier.py +11 -0
- uncountable/types/identifier_t.py +63 -0
- uncountable/types/input_attributes.py +3 -24
- uncountable/types/input_attributes_t.py +30 -0
- uncountable/types/inputs.py +6 -56
- uncountable/types/inputs_t.py +83 -0
- uncountable/types/integration_server.py +9 -0
- uncountable/types/integration_server_t.py +42 -0
- uncountable/types/job_definition.py +27 -0
- uncountable/types/job_definition_t.py +260 -0
- uncountable/types/outputs.py +3 -21
- uncountable/types/outputs_t.py +30 -0
- uncountable/types/overrides.py +10 -0
- uncountable/types/overrides_t.py +49 -0
- uncountable/types/permissions.py +8 -0
- uncountable/types/permissions_t.py +46 -0
- uncountable/types/phases.py +3 -18
- uncountable/types/phases_t.py +27 -0
- uncountable/types/post_base.py +8 -0
- uncountable/types/post_base_t.py +30 -0
- uncountable/types/queued_job.py +16 -0
- uncountable/types/queued_job_t.py +123 -0
- uncountable/types/recipe_identifiers.py +12 -0
- uncountable/types/recipe_identifiers_t.py +76 -0
- uncountable/types/recipe_inputs.py +9 -0
- uncountable/types/recipe_inputs_t.py +30 -0
- uncountable/types/recipe_links.py +4 -45
- uncountable/types/recipe_links_t.py +54 -0
- uncountable/types/recipe_metadata.py +5 -45
- uncountable/types/recipe_metadata_t.py +58 -0
- uncountable/types/recipe_output_metadata.py +3 -19
- uncountable/types/recipe_output_metadata_t.py +28 -0
- uncountable/types/recipe_tags.py +3 -18
- uncountable/types/recipe_tags_t.py +27 -0
- uncountable/types/recipe_workflow_steps.py +14 -0
- uncountable/types/recipe_workflow_steps_t.py +95 -0
- uncountable/types/recipes.py +8 -0
- uncountable/types/recipes_t.py +25 -0
- uncountable/types/response.py +3 -20
- uncountable/types/response_t.py +26 -0
- uncountable/types/secret_retrieval.py +12 -0
- uncountable/types/secret_retrieval_t.py +75 -0
- uncountable/types/units.py +3 -18
- uncountable/types/units_t.py +27 -0
- uncountable/types/users.py +3 -19
- uncountable/types/users_t.py +28 -0
- uncountable/types/webhook_job.py +9 -0
- uncountable/types/webhook_job_t.py +37 -0
- uncountable/types/workflows.py +4 -27
- uncountable/types/workflows_t.py +39 -0
- UncountablePythonSDK-0.0.8.dist-info/METADATA +0 -27
- UncountablePythonSDK-0.0.8.dist-info/RECORD +0 -134
- examples/recipe-import/importer.py +0 -39
- type_spec/external/api/batch/execute_batch.yaml +0 -56
- type_spec/external/api/entity/create_entities.yaml +0 -33
- type_spec/external/api/entity/create_entity.yaml +0 -39
- 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/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/project/get_projects.yaml +0 -42
- type_spec/external/api/project/get_projects_data.yaml +0 -50
- type_spec/external/api/recipe_metadata/get_recipe_metadata_data.yaml +0 -41
- type_spec/external/api/recipes/create_recipes.yaml +0 -47
- type_spec/external/api/recipes/get_curve.yaml +0 -18
- 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 -238
- type_spec/external/api/recipes/set_recipe_inputs.yaml +0 -36
- type_spec/external/api/recipes/set_recipe_outputs.yaml +0 -52
|
@@ -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,27 +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
|
|
8
|
+
from collections.abc import Callable, Mapping, Sequence
|
|
3
9
|
from decimal import Decimal
|
|
4
10
|
from typing import (
|
|
5
11
|
TYPE_CHECKING,
|
|
6
12
|
Any,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Optional,
|
|
10
|
-
Sequence,
|
|
13
|
+
ClassVar,
|
|
14
|
+
Protocol,
|
|
11
15
|
TypeVar,
|
|
12
16
|
Union,
|
|
17
|
+
overload,
|
|
13
18
|
)
|
|
14
19
|
|
|
15
|
-
from pkgs.argument_parser import
|
|
20
|
+
from pkgs.argument_parser import snake_to_camel_case
|
|
16
21
|
from pkgs.serialization import (
|
|
17
22
|
MISSING_SENTRY,
|
|
18
|
-
MissingSentryType,
|
|
19
|
-
MissingType,
|
|
20
23
|
OpaqueKey,
|
|
21
24
|
get_serial_class_data,
|
|
22
25
|
)
|
|
23
26
|
|
|
24
27
|
from ._get_type_for_serialization import SerializationType, get_serialization_type
|
|
28
|
+
from .dataclasses import iterate_fields
|
|
25
29
|
|
|
26
30
|
# Inlined types which otherwise would import from types/base.py
|
|
27
31
|
JsonScalar = Union[str, float, bool, Decimal, None, datetime.datetime, datetime.date]
|
|
@@ -30,53 +34,101 @@ if TYPE_CHECKING:
|
|
|
30
34
|
else:
|
|
31
35
|
JsonValue = Union[JsonScalar, dict[str, Any], list[Any]]
|
|
32
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
|
|
33
46
|
|
|
34
|
-
|
|
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:
|
|
35
57
|
if isinstance(o, OpaqueKey):
|
|
36
58
|
return o
|
|
37
|
-
if isinstance(o, enum.
|
|
59
|
+
if isinstance(o, enum.StrEnum):
|
|
38
60
|
return o.value
|
|
39
61
|
if isinstance(o, str):
|
|
40
62
|
return snake_to_camel_case(o)
|
|
41
|
-
|
|
63
|
+
if isinstance(o, int):
|
|
64
|
+
# we allow dictionaries to use integer keys
|
|
65
|
+
return o
|
|
66
|
+
raise ValueError("Unexpected key type", o)
|
|
42
67
|
|
|
43
68
|
|
|
44
|
-
def _convert_dict(d: Any) ->
|
|
69
|
+
def _convert_dict(d: dict[str, Any]) -> dict[str, JsonValue]:
|
|
45
70
|
return {
|
|
46
|
-
key_convert_to_camelcase(k):
|
|
71
|
+
key_convert_to_camelcase(k): serialize_for_api(v)
|
|
47
72
|
for k, v in d.items()
|
|
48
73
|
if v != MISSING_SENTRY
|
|
49
74
|
}
|
|
50
75
|
|
|
51
76
|
|
|
52
|
-
def _serialize_dict(d: Any) -> dict[str,
|
|
53
|
-
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}
|
|
54
79
|
|
|
55
80
|
|
|
56
|
-
def
|
|
57
|
-
|
|
58
|
-
|
|
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
|
+
return str(value)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclasses.dataclass(kw_only=True)
|
|
93
|
+
class DataclassConversions:
|
|
94
|
+
key_conversions: dict[str, str]
|
|
95
|
+
value_conversion_functions: dict[str, Callable[[Any], JsonValue]]
|
|
59
96
|
|
|
60
|
-
|
|
97
|
+
|
|
98
|
+
@functools.lru_cache(maxsize=10000)
|
|
99
|
+
def _get_dataclass_conversion_lookups(dataclass_type: Any) -> DataclassConversions:
|
|
100
|
+
scd = get_serial_class_data(dataclass_type)
|
|
101
|
+
|
|
102
|
+
key_conversions: dict[str, str] = {}
|
|
103
|
+
value_conversion_functions: dict[str, Callable[[Any], JsonValue]] = {}
|
|
104
|
+
|
|
105
|
+
for field in dataclasses.fields(dataclass_type):
|
|
106
|
+
key = field.name
|
|
61
107
|
if scd.has_unconverted_key(key):
|
|
62
|
-
|
|
63
|
-
|
|
108
|
+
key_conversions[key] = key
|
|
109
|
+
else:
|
|
110
|
+
key_conversions[key] = key_convert_to_camelcase(key)
|
|
64
111
|
|
|
65
|
-
def value_convert(key: Any, value: Any) -> Any:
|
|
66
|
-
if value is None:
|
|
67
|
-
return None
|
|
68
112
|
if scd.has_to_string_value(key):
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return value
|
|
75
|
-
return convert_to_camelcase(value)
|
|
113
|
+
value_conversion_functions[key] = _to_string_value
|
|
114
|
+
elif scd.has_unconverted_value(key):
|
|
115
|
+
value_conversion_functions[key] = identity
|
|
116
|
+
else:
|
|
117
|
+
value_conversion_functions[key] = serialize_for_api
|
|
76
118
|
|
|
119
|
+
return DataclassConversions(
|
|
120
|
+
key_conversions=key_conversions,
|
|
121
|
+
value_conversion_functions=value_conversion_functions,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _convert_dataclass(d: Any) -> dict[str, JsonValue]:
|
|
126
|
+
conversions = _get_dataclass_conversion_lookups(type(d)) # type: ignore[arg-type]
|
|
77
127
|
return {
|
|
78
|
-
|
|
79
|
-
|
|
128
|
+
conversions.key_conversions[k]: (
|
|
129
|
+
conversions.value_conversion_functions[k](v) if v is not None else None
|
|
130
|
+
)
|
|
131
|
+
for k, v in iterate_fields(d)
|
|
80
132
|
if v != MISSING_SENTRY
|
|
81
133
|
}
|
|
82
134
|
|
|
@@ -85,38 +137,54 @@ _SERIALIZATION_FUNCS_STANDARD = {
|
|
|
85
137
|
SerializationType.ENUM: lambda x: str(x.value),
|
|
86
138
|
SerializationType.DATE: lambda x: x.isoformat(),
|
|
87
139
|
SerializationType.TIMEDELTA: lambda x: x.total_seconds(),
|
|
88
|
-
SerializationType.UNKNOWN:
|
|
140
|
+
SerializationType.UNKNOWN: identity,
|
|
89
141
|
}
|
|
90
142
|
|
|
91
|
-
_CONVERSION_SERIALIZATION_FUNCS = {
|
|
143
|
+
_CONVERSION_SERIALIZATION_FUNCS: dict[SerializationType, Callable[[Any], JsonValue]] = {
|
|
92
144
|
**_SERIALIZATION_FUNCS_STANDARD,
|
|
93
145
|
SerializationType.NAMED_TUPLE: lambda x: _convert_dict(x._asdict()),
|
|
94
|
-
SerializationType.ITERABLE: lambda x: [
|
|
146
|
+
SerializationType.ITERABLE: lambda x: [serialize_for_api(v) for v in x],
|
|
95
147
|
SerializationType.DICT: _convert_dict,
|
|
96
148
|
SerializationType.DATACLASS: _convert_dataclass,
|
|
97
149
|
}
|
|
98
150
|
|
|
99
151
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
152
|
+
@overload
|
|
153
|
+
def serialize_for_api(obj: None) -> None: ...
|
|
154
|
+
|
|
103
155
|
|
|
156
|
+
@overload
|
|
157
|
+
def serialize_for_api(obj: dict[str, Any]) -> dict[str, JsonValue]: ...
|
|
104
158
|
|
|
105
|
-
|
|
159
|
+
|
|
160
|
+
@overload
|
|
161
|
+
def serialize_for_api(obj: Dataclass) -> dict[str, JsonValue]: ...
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@overload
|
|
165
|
+
def serialize_for_api(obj: Any) -> JsonValue: ...
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def serialize_for_api(obj: Any) -> JsonValue:
|
|
106
169
|
"""
|
|
107
170
|
Serialize to a parsed-JSON format suitably encoded for API output.
|
|
108
171
|
|
|
109
172
|
Use the CachedParser.parse_api to parse this data.
|
|
110
173
|
"""
|
|
111
174
|
serialization_type = get_serialization_type(type(obj)) # type: ignore
|
|
112
|
-
|
|
175
|
+
if (
|
|
176
|
+
serialization_type == SerializationType.UNKNOWN
|
|
177
|
+
): # performance optimization to not do function lookup
|
|
178
|
+
return obj # type: ignore
|
|
179
|
+
r = _CONVERSION_SERIALIZATION_FUNCS[serialization_type](obj)
|
|
180
|
+
return r
|
|
113
181
|
|
|
114
182
|
|
|
115
183
|
_SERIALIZATION_FUNCS_DICT: dict[
|
|
116
184
|
SerializationType, Callable[[Any], dict[str, JsonValue]]
|
|
117
185
|
] = {
|
|
118
186
|
SerializationType.DICT: _serialize_dict,
|
|
119
|
-
SerializationType.DATACLASS:
|
|
187
|
+
SerializationType.DATACLASS: _serialize_dataclass,
|
|
120
188
|
}
|
|
121
189
|
|
|
122
190
|
|
|
@@ -124,15 +192,10 @@ _SERIALIZATION_FUNCS: dict[SerializationType, Callable[[Any], JsonValue]] = {
|
|
|
124
192
|
**_SERIALIZATION_FUNCS_STANDARD,
|
|
125
193
|
**_SERIALIZATION_FUNCS_DICT,
|
|
126
194
|
SerializationType.NAMED_TUPLE: lambda x: _serialize_dict(x._asdict()),
|
|
127
|
-
SerializationType.ITERABLE: lambda x: [
|
|
195
|
+
SerializationType.ITERABLE: lambda x: [serialize_for_storage(v) for v in x],
|
|
128
196
|
}
|
|
129
197
|
|
|
130
198
|
|
|
131
|
-
def serialize(obj: Any) -> Any:
|
|
132
|
-
"""@DEPRECATED: prefer serialize_for_storage"""
|
|
133
|
-
return serialize_for_storage(obj)
|
|
134
|
-
|
|
135
|
-
|
|
136
199
|
def serialize_for_storage(obj: Any) -> JsonValue:
|
|
137
200
|
"""
|
|
138
201
|
Convert a value into the pseudo-JSON form for
|
|
@@ -141,37 +204,16 @@ def serialize_for_storage(obj: Any) -> JsonValue:
|
|
|
141
204
|
Use the CachedParser.parse_storage to parse this data.
|
|
142
205
|
"""
|
|
143
206
|
serialization_type = get_serialization_type(type(obj)) # type: ignore
|
|
207
|
+
if (
|
|
208
|
+
serialization_type == SerializationType.UNKNOWN
|
|
209
|
+
): # performance optimization to not do function lookup
|
|
210
|
+
return obj # type: ignore
|
|
144
211
|
return _SERIALIZATION_FUNCS[serialization_type](obj)
|
|
145
212
|
|
|
146
213
|
|
|
147
|
-
def serialize_for_storage_dict(obj:
|
|
214
|
+
def serialize_for_storage_dict(obj: dict | Dataclass) -> dict[str, JsonValue]: # type: ignore[type-arg]
|
|
148
215
|
"""
|
|
149
216
|
Same as serialize for storage but guarantees outer object is a dictionary
|
|
150
217
|
"""
|
|
151
|
-
serialization_type = get_serialization_type(type(obj))
|
|
218
|
+
serialization_type = get_serialization_type(type(obj))
|
|
152
219
|
return _SERIALIZATION_FUNCS_DICT[serialization_type](obj)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
def key_convert_to_snake_case(o: Any) -> Any:
|
|
156
|
-
if isinstance(o, OpaqueKey):
|
|
157
|
-
return o
|
|
158
|
-
if isinstance(o, str):
|
|
159
|
-
return camel_to_snake_case(o)
|
|
160
|
-
return o
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def convert_dict_to_snake_case(data: Any) -> Any:
|
|
164
|
-
return {
|
|
165
|
-
key_convert_to_snake_case(k): convert_dict_to_snake_case(v)
|
|
166
|
-
if isinstance(v, dict)
|
|
167
|
-
else v
|
|
168
|
-
for k, v in data.items()
|
|
169
|
-
if v != MISSING_SENTRY
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
T = TypeVar("T")
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def resolve_missing_to_none(val: MissingType[T]) -> Optional[T]:
|
|
177
|
-
return val if not isinstance(val, MissingSentryType) else None
|
|
File without changes
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This processes the directory main/unc/materials/shared/actions_registry and emits actions_registry/action_definitions.tsx
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from collections import defaultdict
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import TypeVar
|
|
10
|
+
|
|
11
|
+
from main.base.types import actions_registry_t
|
|
12
|
+
from pkgs.type_spec import builder
|
|
13
|
+
|
|
14
|
+
from ...argument_parser import CachedParser
|
|
15
|
+
from ..emit_typescript_util import ts_name
|
|
16
|
+
from ..util import rewrite_file
|
|
17
|
+
from .emit_typescript import ActionDefinitionWithArgument, emit_action_definitions
|
|
18
|
+
|
|
19
|
+
key_name = "name"
|
|
20
|
+
key_icon = "icon"
|
|
21
|
+
key_short_description = "short_description"
|
|
22
|
+
key_description = "description"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
TypeT = TypeVar("TypeT")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class InvalidSpecException(Exception):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(kw_only=True)
|
|
33
|
+
class ActionRegistryFileInfo:
|
|
34
|
+
directories: list[str]
|
|
35
|
+
filename: str
|
|
36
|
+
filepath: str
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
ACTIONS_REGISTRY_ROOT = "main/unc/materials/shared/actions_registry/"
|
|
40
|
+
action_definition_parser = CachedParser(
|
|
41
|
+
dict[str, actions_registry_t.ActionDefinitionYaml]
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_action_registry_files_info() -> list[ActionRegistryFileInfo]:
|
|
46
|
+
files_info = []
|
|
47
|
+
for dirname, _, files in os.walk(ACTIONS_REGISTRY_ROOT):
|
|
48
|
+
directories = dirname.replace(ACTIONS_REGISTRY_ROOT, "").split("/")
|
|
49
|
+
for filename in files:
|
|
50
|
+
filepath = os.path.join(dirname, filename)
|
|
51
|
+
if os.path.isfile(filepath) and filepath.endswith(".yaml"):
|
|
52
|
+
files_info.append(
|
|
53
|
+
ActionRegistryFileInfo(
|
|
54
|
+
directories=directories,
|
|
55
|
+
filename=filename.replace(".yaml", ""),
|
|
56
|
+
filepath=filepath,
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
return files_info
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def main() -> None:
|
|
63
|
+
files_info = get_action_registry_files_info()
|
|
64
|
+
action_definitions: defaultdict[str, list[ActionDefinitionWithArgument]] = (
|
|
65
|
+
defaultdict(list)
|
|
66
|
+
)
|
|
67
|
+
all_action_definitions: list[actions_registry_t.ActionDefinitionInternal] = []
|
|
68
|
+
action_definitions_with_arguments_list: list[ActionDefinitionWithArgument] = []
|
|
69
|
+
for file_info in files_info:
|
|
70
|
+
in_action_definitions = action_definition_parser.parse_yaml_file(
|
|
71
|
+
file_info.filepath
|
|
72
|
+
)
|
|
73
|
+
if len(in_action_definitions) == 0:
|
|
74
|
+
continue
|
|
75
|
+
for ref_name, definition in in_action_definitions.items():
|
|
76
|
+
modules = [*file_info.directories]
|
|
77
|
+
# if the actions are stored in index.yaml, parent dir should be treated as module
|
|
78
|
+
if file_info.filename != "index":
|
|
79
|
+
modules.append(file_info.filename)
|
|
80
|
+
|
|
81
|
+
module_str = "_".join(modules)
|
|
82
|
+
action_definition = actions_registry_t.ActionDefinitionInternal(
|
|
83
|
+
name=definition.name,
|
|
84
|
+
short_description=definition.short_description,
|
|
85
|
+
description=definition.description,
|
|
86
|
+
icon=definition.icon,
|
|
87
|
+
ref_name=ref_name,
|
|
88
|
+
module=actions_registry_t.ActionsRegistryModule(
|
|
89
|
+
ts_name(module_str, name_case=builder.NameCase.convert)
|
|
90
|
+
),
|
|
91
|
+
visibility_scope=[
|
|
92
|
+
actions_registry_t.ActionDefinitionVisibilityScope(item)
|
|
93
|
+
for item in definition.visibility_scope
|
|
94
|
+
]
|
|
95
|
+
if definition.visibility_scope is not None
|
|
96
|
+
else None,
|
|
97
|
+
)
|
|
98
|
+
action_definitions_with_arguments_list.append(
|
|
99
|
+
ActionDefinitionWithArgument(
|
|
100
|
+
module=module_str,
|
|
101
|
+
ref_name=ref_name,
|
|
102
|
+
arguments=definition.arguments,
|
|
103
|
+
definition=action_definition,
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
all_action_definitions.append(action_definition)
|
|
107
|
+
action_definitions_with_arguments_list = sorted(
|
|
108
|
+
action_definitions_with_arguments_list,
|
|
109
|
+
key=lambda item: (item.module, item.ref_name),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
for action_definition_with_argument in action_definitions_with_arguments_list:
|
|
113
|
+
action_definitions[action_definition_with_argument.module].append(
|
|
114
|
+
action_definition_with_argument
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
ts_content = emit_action_definitions(action_definitions)
|
|
118
|
+
rewrite_file(
|
|
119
|
+
"main/site/js/materials/base/actions_registry/action_definitions.tsx",
|
|
120
|
+
ts_content,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
sys.exit(0)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
main()
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import io
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from main.base.types import actions_registry_t
|
|
6
|
+
|
|
7
|
+
from ...type_spec import builder
|
|
8
|
+
from ..emit_typescript_util import (
|
|
9
|
+
INDENT,
|
|
10
|
+
MODIFY_NOTICE,
|
|
11
|
+
resolve_namespace_ref,
|
|
12
|
+
ts_name,
|
|
13
|
+
ts_type_name,
|
|
14
|
+
)
|
|
15
|
+
from ..util import encode_common_string
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _action_symbol_name(
|
|
19
|
+
action_definition: actions_registry_t.ActionDefinitionInternal,
|
|
20
|
+
) -> str:
|
|
21
|
+
return f"{ts_name(action_definition.ref_name, name_case=builder.NameCase.convert)}"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _action_type_name(ref_name: str) -> str:
|
|
25
|
+
return f"{ts_type_name(ref_name)}"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _action_namespace_name(name: str) -> str:
|
|
29
|
+
return f"{resolve_namespace_ref(builder.SpecNamespace(name=name))}"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _action_module_name_base(module: str) -> str:
|
|
33
|
+
return f"{ts_name(module, name_case=builder.NameCase.convert)}"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _action_module_name_obj(module: str) -> str:
|
|
37
|
+
return f"{_action_module_name_base(module)}Actions"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _action_module_name(module: str) -> str:
|
|
41
|
+
return f"ActionsRegistryT.ActionsRegistryModule.{_action_module_name_base(module)}"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass(kw_only=True)
|
|
45
|
+
class ActionDefinitionWithArgument:
|
|
46
|
+
module: str
|
|
47
|
+
ref_name: str
|
|
48
|
+
arguments: str | None
|
|
49
|
+
definition: actions_registry_t.ActionDefinitionInternal
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _emit_imports(
|
|
53
|
+
action_definitions: defaultdict[str, list[ActionDefinitionWithArgument]],
|
|
54
|
+
) -> str:
|
|
55
|
+
out = io.StringIO()
|
|
56
|
+
namespaces = set()
|
|
57
|
+
for definitions in action_definitions.values():
|
|
58
|
+
for definition in definitions:
|
|
59
|
+
if definition.arguments is not None:
|
|
60
|
+
argument_parts = definition.arguments.split(".")
|
|
61
|
+
namespace = argument_parts[0]
|
|
62
|
+
namespaces.add(namespace)
|
|
63
|
+
namespaces_to_import = ", ".join(
|
|
64
|
+
sorted([f"type {_action_namespace_name(item)}" for item in list(namespaces)])
|
|
65
|
+
)
|
|
66
|
+
out.write(
|
|
67
|
+
f'import {{ ActionsRegistryT, {namespaces_to_import} }} from "unc_types"\n\n'
|
|
68
|
+
)
|
|
69
|
+
out.write(MODIFY_NOTICE)
|
|
70
|
+
return out.getvalue()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def emit_action_definitions(
|
|
74
|
+
action_definitions: defaultdict[str, list[ActionDefinitionWithArgument]],
|
|
75
|
+
) -> str:
|
|
76
|
+
out = io.StringIO()
|
|
77
|
+
out.write(MODIFY_NOTICE)
|
|
78
|
+
out.write("\n")
|
|
79
|
+
out.write(_emit_imports(action_definitions))
|
|
80
|
+
modules = []
|
|
81
|
+
for key, values in action_definitions.items():
|
|
82
|
+
out.write(MODIFY_NOTICE)
|
|
83
|
+
modules.append(key)
|
|
84
|
+
out.write(f"export const {_action_module_name_obj(key)} = {{\n")
|
|
85
|
+
for item in values:
|
|
86
|
+
out.write(MODIFY_NOTICE)
|
|
87
|
+
out.write(_emit_action_definition(item.definition, item.arguments, INDENT))
|
|
88
|
+
out.write("}\n")
|
|
89
|
+
|
|
90
|
+
out.write(MODIFY_NOTICE)
|
|
91
|
+
out.write("\n")
|
|
92
|
+
out.write(MODIFY_NOTICE)
|
|
93
|
+
out.write("\n")
|
|
94
|
+
out.write("export const actionDefinitions = {\n")
|
|
95
|
+
for module in modules:
|
|
96
|
+
out.write(
|
|
97
|
+
f"{INDENT}[{_action_module_name(module)}]: {_action_module_name_obj(module)},\n"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
out.write("}\n")
|
|
101
|
+
out.write(_emit_action_definition_types(modules, indent=""))
|
|
102
|
+
out.write(MODIFY_NOTICE)
|
|
103
|
+
out.write("\n")
|
|
104
|
+
|
|
105
|
+
return out.getvalue()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _get_argument_type(arguments: str | None) -> str | None:
|
|
109
|
+
if arguments is None:
|
|
110
|
+
return None
|
|
111
|
+
argument_parts = arguments.split(".")
|
|
112
|
+
namespace = argument_parts[0]
|
|
113
|
+
type_name = argument_parts[1]
|
|
114
|
+
return f"{_action_namespace_name(namespace)}.{type_name}"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _emit_action_definition(
|
|
118
|
+
action_definition: actions_registry_t.ActionDefinitionInternal,
|
|
119
|
+
arguments: str | None,
|
|
120
|
+
indent: str,
|
|
121
|
+
) -> str:
|
|
122
|
+
out = io.StringIO()
|
|
123
|
+
|
|
124
|
+
sub_indent = indent + INDENT
|
|
125
|
+
argument_type = _get_argument_type(arguments)
|
|
126
|
+
argument_type = f"<{argument_type}>" if argument_type is not None else ""
|
|
127
|
+
out.write(f"{indent}{_action_symbol_name(action_definition)}: {{\n")
|
|
128
|
+
out.write(f"{sub_indent}name: {encode_common_string(action_definition.name)},\n")
|
|
129
|
+
if action_definition.icon is not None:
|
|
130
|
+
out.write(
|
|
131
|
+
f"{sub_indent}icon: {encode_common_string(action_definition.icon)},\n"
|
|
132
|
+
)
|
|
133
|
+
out.write(
|
|
134
|
+
f"{sub_indent}shortDescription: {encode_common_string(action_definition.short_description)},\n"
|
|
135
|
+
)
|
|
136
|
+
out.write(
|
|
137
|
+
f"{sub_indent}description: {encode_common_string(action_definition.description)},\n"
|
|
138
|
+
)
|
|
139
|
+
out.write(
|
|
140
|
+
f"{sub_indent}refName: {encode_common_string(action_definition.ref_name)},\n"
|
|
141
|
+
)
|
|
142
|
+
out.write(f"{sub_indent}module: {_action_module_name(action_definition.module)},\n")
|
|
143
|
+
if (
|
|
144
|
+
action_definition.visibility_scope is not None
|
|
145
|
+
and len(action_definition.visibility_scope) > 0
|
|
146
|
+
):
|
|
147
|
+
out.write(
|
|
148
|
+
f"{sub_indent}visibilityScope: {_emit_visibility_scope(action_definition.visibility_scope)},\n"
|
|
149
|
+
)
|
|
150
|
+
out.write(f"{indent}}} as ActionsRegistryT.ActionDefinition{argument_type},\n")
|
|
151
|
+
return out.getvalue()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _emit_action_definition_types(modules: list[str], indent: str) -> str:
|
|
155
|
+
out = io.StringIO()
|
|
156
|
+
|
|
157
|
+
sub_indent = indent + INDENT
|
|
158
|
+
out.write(
|
|
159
|
+
f"{indent}type RefNameKeys<M extends ActionsRegistryT.ActionsRegistryModule> = keyof (typeof actionDefinitions)[M]\n"
|
|
160
|
+
)
|
|
161
|
+
out.write(
|
|
162
|
+
f"{indent}type ActionDefinitionIdentifierGetter<M extends ActionsRegistryT.ActionsRegistryModule> = {{ module: M; refName: RefNameKeys<M> }}\n"
|
|
163
|
+
)
|
|
164
|
+
out.write(f"{indent}export type ActionDefinitionIdentifier =\n")
|
|
165
|
+
for module in modules:
|
|
166
|
+
out.write(
|
|
167
|
+
f"{sub_indent}| ActionDefinitionIdentifierGetter<{_action_module_name(module)}>\n"
|
|
168
|
+
)
|
|
169
|
+
out.write("\n")
|
|
170
|
+
return out.getvalue()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _emit_visibility_scope(
|
|
174
|
+
visibility_scope: list[actions_registry_t.ActionDefinitionVisibilityScope],
|
|
175
|
+
) -> str:
|
|
176
|
+
visibility_scope_types = ",".join([
|
|
177
|
+
f"ActionsRegistryT.ActionDefinitionVisibilityScope.{ts_name(visibility_item, name_case=builder.NameCase.convert)}"
|
|
178
|
+
for visibility_item in visibility_scope
|
|
179
|
+
if visibility_item is not None
|
|
180
|
+
])
|
|
181
|
+
|
|
182
|
+
return f"[ {visibility_scope_types} ]"
|