UncountablePythonSDK 0.0.16__py3-none-any.whl → 0.0.18__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.16.dist-info → UncountablePythonSDK-0.0.18.dist-info}/METADATA +14 -1
- {UncountablePythonSDK-0.0.16.dist-info → UncountablePythonSDK-0.0.18.dist-info}/RECORD +81 -33
- {UncountablePythonSDK-0.0.16.dist-info → UncountablePythonSDK-0.0.18.dist-info}/top_level.txt +1 -0
- docs/.gitignore +1 -0
- docs/conf.py +52 -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/create_entity.py +23 -16
- pkgs/argument_parser/_is_enum.py +1 -1
- pkgs/argument_parser/argument_parser.py +26 -19
- pkgs/serialization/serial_class.py +3 -3
- pkgs/serialization_util/_get_type_for_serialization.py +1 -3
- pkgs/serialization_util/serialization_helpers.py +1 -3
- pkgs/strenum_compat/strenum_compat.py +1 -9
- pkgs/type_spec/actions_registry/__init__.py +0 -0
- pkgs/type_spec/actions_registry/__main__.py +114 -0
- pkgs/type_spec/actions_registry/emit_typescript.py +120 -0
- pkgs/type_spec/builder.py +14 -10
- pkgs/type_spec/config.py +3 -2
- pkgs/type_spec/emit_python.py +54 -17
- pkgs/type_spec/emit_typescript.py +8 -9
- pkgs/type_spec/emit_typescript_util.py +1 -2
- pkgs/type_spec/load_types.py +2 -1
- pkgs/type_spec/open_api_util.py +2 -2
- pkgs/type_spec/parts/base.py.prepart +2 -1
- pkgs/type_spec/util.py +9 -9
- pkgs/type_spec/value_spec/__main__.py +2 -2
- pkgs/type_spec/value_spec/emit_python.py +1 -0
- type_spec/external/api/batch/execute_batch_load_async.yaml +18 -0
- type_spec/external/api/chemical/convert_chemical_formats.yaml +33 -0
- type_spec/external/api/entity/create_entities.yaml +1 -1
- type_spec/external/api/entity/create_entity.yaml +1 -1
- type_spec/external/api/id_source/list_id_source.yaml +35 -0
- type_spec/external/api/id_source/match_id_source.yaml +32 -0
- type_spec/external/api/recipe_links/create_recipe_link.yaml +25 -0
- type_spec/external/api/recipes/associate_recipe_as_input.yaml +19 -0
- type_spec/external/api/recipes/associate_recipe_as_lot.yaml +19 -0
- type_spec/external/api/recipes/create_recipe.yaml +38 -0
- type_spec/external/api/recipes/get_recipes_data.yaml +21 -21
- type_spec/external/api/recipes/set_recipe_inputs.yaml +6 -0
- type_spec/external/api/recipes/set_recipe_metadata.yaml +19 -0
- type_spec/external/api/triggers/run_trigger.yaml +18 -0
- uncountable/core/client.py +13 -14
- uncountable/types/__init__.py +30 -0
- uncountable/types/api/batch/execute_batch_load_async.py +35 -0
- uncountable/types/api/chemical/__init__.py +1 -0
- uncountable/types/api/chemical/convert_chemical_formats.py +50 -0
- uncountable/types/api/entity/create_entities.py +1 -1
- uncountable/types/api/entity/create_entity.py +1 -1
- uncountable/types/api/id_source/__init__.py +1 -0
- uncountable/types/api/id_source/list_id_source.py +46 -0
- uncountable/types/api/id_source/match_id_source.py +48 -0
- uncountable/types/api/recipe_links/__init__.py +1 -0
- uncountable/types/api/recipe_links/create_recipe_link.py +39 -0
- uncountable/types/api/recipes/associate_recipe_as_input.py +35 -0
- uncountable/types/api/recipes/associate_recipe_as_lot.py +36 -0
- uncountable/types/api/recipes/create_recipe.py +43 -0
- uncountable/types/api/recipes/set_recipe_inputs.py +2 -0
- uncountable/types/api/recipes/set_recipe_metadata.py +36 -0
- uncountable/types/api/triggers/__init__.py +1 -0
- uncountable/types/api/triggers/run_trigger.py +36 -0
- uncountable/types/async_batch.py +45 -0
- uncountable/types/base.py +2 -1
- uncountable/types/chemical_structure.py +27 -0
- uncountable/types/client_base.py +404 -2
- uncountable/types/id_source.py +49 -0
- uncountable/types/identifier.py +54 -0
- uncountable/types/recipe_identifiers.py +62 -0
- {UncountablePythonSDK-0.0.16.dist-info → UncountablePythonSDK-0.0.18.dist-info}/WHEEL +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
|
-
from
|
|
5
|
-
|
|
6
|
-
from
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
from typing import Any, Optional, TypeVar, cast
|
|
7
7
|
|
|
8
8
|
_ClassT = TypeVar("_ClassT")
|
|
9
9
|
|
|
File without changes
|
|
@@ -0,0 +1,114 @@
|
|
|
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 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[actions_registry_t.ActionDefinition]] = (
|
|
65
|
+
defaultdict(list)
|
|
66
|
+
)
|
|
67
|
+
all_action_definitions: list[actions_registry_t.ActionDefinition] = []
|
|
68
|
+
|
|
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
|
+
all_action_definitions.append(
|
|
83
|
+
actions_registry_t.ActionDefinition(
|
|
84
|
+
name=definition.name,
|
|
85
|
+
short_description=definition.short_description,
|
|
86
|
+
description=definition.description,
|
|
87
|
+
icon=definition.icon,
|
|
88
|
+
ref_name=ref_name,
|
|
89
|
+
module=actions_registry_t.ActionsRegistryModule(
|
|
90
|
+
ts_name(module_str, name_case=builder.NameCase.convert)
|
|
91
|
+
),
|
|
92
|
+
visibility_scope=[
|
|
93
|
+
actions_registry_t.ActionDefinitionVisibilityScope(item)
|
|
94
|
+
for item in definition.visibility_scope
|
|
95
|
+
]
|
|
96
|
+
if definition.visibility_scope is not None
|
|
97
|
+
else None,
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
all_action_definitions = sorted(
|
|
101
|
+
all_action_definitions, key=lambda item: (item.module, item.ref_name)
|
|
102
|
+
)
|
|
103
|
+
for action_definition in all_action_definitions:
|
|
104
|
+
action_definitions[action_definition.module].append(action_definition)
|
|
105
|
+
ts_content = emit_action_definitions(action_definitions)
|
|
106
|
+
rewrite_file(
|
|
107
|
+
"main/site/js/materials/base/actions_registry/action_definitions.tsx",
|
|
108
|
+
ts_content,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
sys.exit(0)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
main()
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import io
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
|
|
4
|
+
from main.base.types import actions_registry_t
|
|
5
|
+
|
|
6
|
+
from ...type_spec import builder
|
|
7
|
+
from ..emit_typescript_util import INDENT, MODIFY_NOTICE, ts_name
|
|
8
|
+
from ..util import encode_common_string
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _action_symbol_name(action_definition: actions_registry_t.ActionDefinition) -> str:
|
|
12
|
+
return f"{ts_name(action_definition.ref_name, name_case=builder.NameCase.convert)}"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _action_module_name_base(module: str) -> str:
|
|
16
|
+
return f"{ts_name(module, name_case=builder.NameCase.convert)}"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _action_module_name_obj(module: str) -> str:
|
|
20
|
+
return f"{_action_module_name_base(module)}Actions"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _action_module_name(module: str) -> str:
|
|
24
|
+
return f"ActionsRegistryT.ActionsRegistryModule.{_action_module_name_base(module)}"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def emit_action_definitions(
|
|
28
|
+
action_definitions: defaultdict[str, list[actions_registry_t.ActionDefinition]],
|
|
29
|
+
) -> str:
|
|
30
|
+
out = io.StringIO()
|
|
31
|
+
out.write(MODIFY_NOTICE)
|
|
32
|
+
out.write("\n")
|
|
33
|
+
out.write('import { ActionsRegistryT } from "unc_mat/types"\n\n')
|
|
34
|
+
out.write(MODIFY_NOTICE)
|
|
35
|
+
modules = []
|
|
36
|
+
for key, values in action_definitions.items():
|
|
37
|
+
out.write(MODIFY_NOTICE)
|
|
38
|
+
modules.append(key)
|
|
39
|
+
out.write(f"export const {_action_module_name_obj(key)} = {{\n")
|
|
40
|
+
for action_definition in values:
|
|
41
|
+
out.write(MODIFY_NOTICE)
|
|
42
|
+
out.write(_emit_action_definition(action_definition, INDENT))
|
|
43
|
+
out.write("}\n")
|
|
44
|
+
|
|
45
|
+
out.write(MODIFY_NOTICE)
|
|
46
|
+
out.write("\n")
|
|
47
|
+
out.write("export const actionDefinitions = {\n")
|
|
48
|
+
for module in modules:
|
|
49
|
+
out.write(
|
|
50
|
+
f"{INDENT}[{_action_module_name(module)}]: {_action_module_name_obj(module)},\n"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
out.write("}\n")
|
|
54
|
+
out.write(_emit_action_definition_types(modules, indent=""))
|
|
55
|
+
out.write(MODIFY_NOTICE)
|
|
56
|
+
out.write("\n")
|
|
57
|
+
|
|
58
|
+
return out.getvalue()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _emit_action_definition(
|
|
62
|
+
action_definition: actions_registry_t.ActionDefinition, indent: str
|
|
63
|
+
) -> str:
|
|
64
|
+
out = io.StringIO()
|
|
65
|
+
|
|
66
|
+
sub_indent = indent + INDENT
|
|
67
|
+
out.write(f"{indent}{_action_symbol_name(action_definition)}: {{\n")
|
|
68
|
+
out.write(f"{sub_indent}name: {encode_common_string(action_definition.name)},\n")
|
|
69
|
+
if action_definition.icon is not None:
|
|
70
|
+
out.write(f"{sub_indent}icon: {encode_common_string(action_definition.icon)},\n")
|
|
71
|
+
out.write(
|
|
72
|
+
f"{sub_indent}shortDescription: {encode_common_string(action_definition.short_description)},\n"
|
|
73
|
+
)
|
|
74
|
+
out.write(
|
|
75
|
+
f"{sub_indent}description: {encode_common_string(action_definition.description)},\n"
|
|
76
|
+
)
|
|
77
|
+
out.write(
|
|
78
|
+
f"{sub_indent}refName: {encode_common_string(action_definition.ref_name)},\n"
|
|
79
|
+
)
|
|
80
|
+
out.write(f"{sub_indent}module: {_action_module_name(action_definition.module)},\n")
|
|
81
|
+
if (
|
|
82
|
+
action_definition.visibility_scope is not None
|
|
83
|
+
and len(action_definition.visibility_scope) > 0
|
|
84
|
+
):
|
|
85
|
+
out.write(
|
|
86
|
+
f"{sub_indent}visibilityScope: {_emit_visibility_scope(action_definition.visibility_scope)},\n"
|
|
87
|
+
)
|
|
88
|
+
out.write(f"{indent}}},\n")
|
|
89
|
+
return out.getvalue()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _emit_action_definition_types(modules: list[str], indent: str) -> str:
|
|
93
|
+
out = io.StringIO()
|
|
94
|
+
|
|
95
|
+
sub_indent = indent + INDENT
|
|
96
|
+
out.write(
|
|
97
|
+
f"{indent}type RefNameKeys<M extends ActionsRegistryT.ActionsRegistryModule> = keyof (typeof actionDefinitions)[M]\n"
|
|
98
|
+
)
|
|
99
|
+
out.write(
|
|
100
|
+
f"{indent}type ActionDefinitionIdentifierGetter<M extends ActionsRegistryT.ActionsRegistryModule> = {{ module: M; refName: RefNameKeys<M> }}\n"
|
|
101
|
+
)
|
|
102
|
+
out.write(f"{indent}export type ActionDefinitionIdentifier =\n")
|
|
103
|
+
for module in modules:
|
|
104
|
+
out.write(
|
|
105
|
+
f"{sub_indent}| ActionDefinitionIdentifierGetter<{_action_module_name(module)}>\n"
|
|
106
|
+
)
|
|
107
|
+
out.write("\n")
|
|
108
|
+
return out.getvalue()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _emit_visibility_scope(
|
|
112
|
+
visibility_scope: list[actions_registry_t.ActionDefinitionVisibilityScope],
|
|
113
|
+
) -> str:
|
|
114
|
+
visibility_scope_types = ",".join([
|
|
115
|
+
f"ActionsRegistryT.ActionDefinitionVisibilityScope.{ts_name(visibility_item, name_case=builder.NameCase.convert)}"
|
|
116
|
+
for visibility_item in visibility_scope
|
|
117
|
+
if visibility_item is not None
|
|
118
|
+
])
|
|
119
|
+
|
|
120
|
+
return f"[ {visibility_scope_types} ]"
|
pkgs/type_spec/builder.py
CHANGED
|
@@ -9,22 +9,22 @@ import os
|
|
|
9
9
|
import re
|
|
10
10
|
from collections import defaultdict
|
|
11
11
|
from dataclasses import MISSING, dataclass
|
|
12
|
-
from enum import Enum, auto
|
|
13
|
-
from typing import Any,
|
|
12
|
+
from enum import Enum, StrEnum, auto
|
|
13
|
+
from typing import Any, Optional
|
|
14
14
|
|
|
15
15
|
from . import util
|
|
16
16
|
from .util import parse_type_str, unused
|
|
17
17
|
|
|
18
|
-
RawDict =
|
|
18
|
+
RawDict = dict[Any, Any]
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
class PropertyExtant(
|
|
21
|
+
class PropertyExtant(StrEnum):
|
|
22
22
|
required = "required"
|
|
23
23
|
optional = "optional"
|
|
24
24
|
missing = "missing"
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class PropertyConvertValue(
|
|
27
|
+
class PropertyConvertValue(StrEnum):
|
|
28
28
|
# Base conversion on underlying types
|
|
29
29
|
auto = "auto"
|
|
30
30
|
# Always convert the value (Not needed yet, thus not supported)
|
|
@@ -52,7 +52,7 @@ class SpecProperty:
|
|
|
52
52
|
ext_info: Any = None
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
class NameCase(
|
|
55
|
+
class NameCase(StrEnum):
|
|
56
56
|
convert = "convert"
|
|
57
57
|
preserve = "preserve"
|
|
58
58
|
# Upper-case in JavaScript, convert otherwise. This is a compatibilty
|
|
@@ -60,7 +60,7 @@ class NameCase(str, Enum):
|
|
|
60
60
|
js_upper = "js_upper"
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
class BaseTypeName(
|
|
63
|
+
class BaseTypeName(StrEnum):
|
|
64
64
|
"""
|
|
65
65
|
Base types that are supported.
|
|
66
66
|
"""
|
|
@@ -92,7 +92,7 @@ class BaseTypeName(str, Enum):
|
|
|
92
92
|
s_object = "Object"
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
class DefnTypeName(
|
|
95
|
+
class DefnTypeName(StrEnum):
|
|
96
96
|
# Type is a named alias of another type
|
|
97
97
|
s_alias = "Alias"
|
|
98
98
|
# Type is imported from an external source (opaque to type_spec)
|
|
@@ -656,7 +656,7 @@ TOKEN_EMIT_TYPE_INFO = "$emit_type_info"
|
|
|
656
656
|
TOKEN_IMPORT = "$import"
|
|
657
657
|
|
|
658
658
|
|
|
659
|
-
class RouteMethod(
|
|
659
|
+
class RouteMethod(StrEnum):
|
|
660
660
|
post = "post"
|
|
661
661
|
get = "get"
|
|
662
662
|
delete = "delete"
|
|
@@ -664,7 +664,7 @@ class RouteMethod(str, Enum):
|
|
|
664
664
|
put = "put"
|
|
665
665
|
|
|
666
666
|
|
|
667
|
-
class ResultType(
|
|
667
|
+
class ResultType(StrEnum):
|
|
668
668
|
json = "json"
|
|
669
669
|
binary = "binary"
|
|
670
670
|
|
|
@@ -747,6 +747,10 @@ class SpecEndpoint:
|
|
|
747
747
|
self.is_external = self.path_root == "api/external"
|
|
748
748
|
self.has_attachment = data.get("has_attachment", False)
|
|
749
749
|
|
|
750
|
+
assert (
|
|
751
|
+
not is_sdk or self.desc is not None
|
|
752
|
+
), f"Endpoint description required for SDK endpoints, missing: {path}"
|
|
753
|
+
|
|
750
754
|
|
|
751
755
|
def _parse_const(
|
|
752
756
|
builder: SpecBuilder,
|
pkgs/type_spec/config.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from collections.abc import Callable, Mapping
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
from decimal import Decimal
|
|
4
|
-
from typing import
|
|
5
|
+
from typing import Self, TypeVar
|
|
5
6
|
|
|
6
7
|
import yaml
|
|
7
8
|
|
|
@@ -96,7 +97,7 @@ class Config:
|
|
|
96
97
|
_T = TypeVar("_T")
|
|
97
98
|
|
|
98
99
|
|
|
99
|
-
def _parse_language(config_class:
|
|
100
|
+
def _parse_language(config_class: type[_T], raw_value: ConfigValueType) -> _T:
|
|
100
101
|
assert isinstance(raw_value, dict), "expecting language config to have key/values."
|
|
101
102
|
return config_class(**raw_value)
|
|
102
103
|
|
pkgs/type_spec/emit_python.py
CHANGED
|
@@ -2,7 +2,7 @@ import io
|
|
|
2
2
|
import os
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from decimal import Decimal
|
|
5
|
-
from typing import Any, Optional
|
|
5
|
+
from typing import Any, Optional
|
|
6
6
|
|
|
7
7
|
from . import builder, util
|
|
8
8
|
from .config import PythonConfig
|
|
@@ -25,8 +25,8 @@ END_ALL_EXPORTS = "]\n"
|
|
|
25
25
|
@dataclass(kw_only=True)
|
|
26
26
|
class TrackingContext:
|
|
27
27
|
namespace: Optional[builder.SpecNamespace] = None
|
|
28
|
-
namespaces:
|
|
29
|
-
names:
|
|
28
|
+
namespaces: set[builder.SpecNamespace] = field(default_factory=set)
|
|
29
|
+
names: set[str] = field(default_factory=set)
|
|
30
30
|
|
|
31
31
|
use_enum: bool = False
|
|
32
32
|
use_serial_string_enum: bool = False
|
|
@@ -119,6 +119,9 @@ def _emit_value(ctx: TrackingContext, stype: builder.SpecType, value: Any) -> st
|
|
|
119
119
|
# Note that decimal requires the `!decimal 123.12` style notation in the YAML
|
|
120
120
|
# file since PyYaml parses numbers as float, unfortuantely
|
|
121
121
|
assert isinstance(value, (Decimal, int))
|
|
122
|
+
if isinstance(value, int):
|
|
123
|
+
# skip quotes for integers
|
|
124
|
+
return f"Decimal({value})"
|
|
122
125
|
return f'Decimal("{value}")'
|
|
123
126
|
elif isinstance(stype, builder.SpecTypeInstance):
|
|
124
127
|
if stype.defn_type.is_base_type(builder.BaseTypeName.s_list):
|
|
@@ -220,7 +223,7 @@ def _emit_types(*, builder: builder.SpecBuilder, config: PythonConfig) -> None:
|
|
|
220
223
|
exports_out = io.StringIO()
|
|
221
224
|
exports_out.write(START_ALL_EXPORTS)
|
|
222
225
|
|
|
223
|
-
all_dirs:
|
|
226
|
+
all_dirs: set[str] = set()
|
|
224
227
|
|
|
225
228
|
for namespace in sorted(
|
|
226
229
|
builder.namespaces.values(),
|
|
@@ -347,6 +350,34 @@ def _validate_supports_handler_generation(
|
|
|
347
350
|
return stype
|
|
348
351
|
|
|
349
352
|
|
|
353
|
+
def _emit_endpoint_invocation_docstring(
|
|
354
|
+
ctx: Context,
|
|
355
|
+
endpoint: builder.SpecEndpoint,
|
|
356
|
+
arguments_type: builder.SpecTypeDefnObject,
|
|
357
|
+
) -> None:
|
|
358
|
+
has_argument_desc = arguments_type.properties is not None and any(
|
|
359
|
+
prop.desc is not None for prop in arguments_type.properties.values()
|
|
360
|
+
)
|
|
361
|
+
has_endpoint_desc = endpoint.desc
|
|
362
|
+
if not has_argument_desc and not has_endpoint_desc:
|
|
363
|
+
return
|
|
364
|
+
|
|
365
|
+
FULL_INDENT = INDENT * 2
|
|
366
|
+
ctx.out.write(FULL_INDENT)
|
|
367
|
+
ctx.out.write('"""')
|
|
368
|
+
|
|
369
|
+
if endpoint.desc is not None and has_endpoint_desc:
|
|
370
|
+
ctx.out.write(f"{endpoint.desc}\n")
|
|
371
|
+
ctx.out.write("\n")
|
|
372
|
+
|
|
373
|
+
if arguments_type.properties is not None and has_argument_desc:
|
|
374
|
+
for prop in arguments_type.properties.values():
|
|
375
|
+
if prop.desc:
|
|
376
|
+
ctx.out.write(f"{FULL_INDENT}:param {prop.name}: {prop.desc}\n")
|
|
377
|
+
|
|
378
|
+
ctx.out.write(f'{FULL_INDENT}"""\n')
|
|
379
|
+
|
|
380
|
+
|
|
350
381
|
def _emit_endpoint_invocation_function(
|
|
351
382
|
ctx: Context, namespace: builder.SpecNamespace
|
|
352
383
|
) -> None:
|
|
@@ -393,8 +424,14 @@ def _emit_endpoint_invocation_function(
|
|
|
393
424
|
class_out=ctx.out,
|
|
394
425
|
)
|
|
395
426
|
ctx.out.write(f"{INDENT}) -> {refer_to(ctx=ctx, stype=data_type)}:")
|
|
396
|
-
|
|
397
427
|
ctx.out.write("\n")
|
|
428
|
+
|
|
429
|
+
_emit_endpoint_invocation_docstring(
|
|
430
|
+
ctx=ctx,
|
|
431
|
+
endpoint=endpoint,
|
|
432
|
+
arguments_type=arguments_type,
|
|
433
|
+
)
|
|
434
|
+
|
|
398
435
|
ctx.out.write(f"{INDENT}{INDENT}args = {refer_to(ctx=ctx, stype=arguments_type)}(")
|
|
399
436
|
if has_arguments:
|
|
400
437
|
assert arguments_type.properties is not None
|
|
@@ -466,10 +503,10 @@ def _emit_string_enum(ctx: Context, stype: builder.SpecTypeDefnStringEnum) -> No
|
|
|
466
503
|
|
|
467
504
|
@dataclass
|
|
468
505
|
class EmittedPropertiesMetadata:
|
|
469
|
-
unconverted_keys:
|
|
470
|
-
unconverted_values:
|
|
471
|
-
to_string_values:
|
|
472
|
-
parse_require:
|
|
506
|
+
unconverted_keys: set[str]
|
|
507
|
+
unconverted_values: set[str]
|
|
508
|
+
to_string_values: set[str]
|
|
509
|
+
parse_require: set[str]
|
|
473
510
|
|
|
474
511
|
|
|
475
512
|
def _emit_type_properties(
|
|
@@ -480,10 +517,10 @@ def _emit_type_properties(
|
|
|
480
517
|
num_indent: int = 1,
|
|
481
518
|
separator: str = "\n",
|
|
482
519
|
) -> EmittedPropertiesMetadata:
|
|
483
|
-
unconverted_keys:
|
|
484
|
-
unconverted_values:
|
|
485
|
-
to_string_values:
|
|
486
|
-
parse_require:
|
|
520
|
+
unconverted_keys: set[str] = set()
|
|
521
|
+
unconverted_values: set[str] = set()
|
|
522
|
+
to_string_values: set[str] = set()
|
|
523
|
+
parse_require: set[str] = set()
|
|
487
524
|
|
|
488
525
|
if stype.properties is not None and len(stype.properties) > 0:
|
|
489
526
|
|
|
@@ -777,7 +814,7 @@ ROUTES: list[DynamicRouteType] = [
|
|
|
777
814
|
def _emit_namespace_imports(
|
|
778
815
|
*,
|
|
779
816
|
out: io.StringIO,
|
|
780
|
-
namespaces:
|
|
817
|
+
namespaces: set[builder.SpecNamespace],
|
|
781
818
|
from_namespace: Optional[builder.SpecNamespace],
|
|
782
819
|
config: PythonConfig,
|
|
783
820
|
) -> None:
|
|
@@ -810,7 +847,7 @@ def _emit_id_source(*, builder: builder.SpecBuilder, config: PythonConfig) -> No
|
|
|
810
847
|
return None
|
|
811
848
|
enum_out = io.StringIO()
|
|
812
849
|
enum_out.write(f"{LINT_HEADER}{MODIFY_NOTICE}\n")
|
|
813
|
-
enum_out.write("from typing import Literal,
|
|
850
|
+
enum_out.write("from typing import Literal, Union\n")
|
|
814
851
|
enum_out.write("from pkgs.strenum_compat import StrEnum\n")
|
|
815
852
|
|
|
816
853
|
ctx = TrackingContext()
|
|
@@ -825,13 +862,13 @@ def _emit_id_source(*, builder: builder.SpecBuilder, config: PythonConfig) -> No
|
|
|
825
862
|
)
|
|
826
863
|
|
|
827
864
|
known_keys = []
|
|
828
|
-
enum_out.write("\nENUM_MAP: dict[str,
|
|
865
|
+
enum_out.write("\nENUM_MAP: dict[str, type[StrEnum]] = {\n")
|
|
829
866
|
for key in sorted(named_enums.keys()):
|
|
830
867
|
enum_out.write(f'"{key}": {named_enums[key]},\n')
|
|
831
868
|
known_keys.append(f'Literal["{key}"]')
|
|
832
869
|
enum_out.write(f"}}\n{MODIFY_NOTICE}\n")
|
|
833
870
|
|
|
834
|
-
enum_out.write(f"\nKnownEnumsType = Union[
|
|
871
|
+
enum_out.write(f"\nKnownEnumsType = Union[\n{INDENT}")
|
|
835
872
|
enum_out.write(f",\n{INDENT}".join(known_keys))
|
|
836
873
|
enum_out.write(f"\n]\n{MODIFY_NOTICE}\n")
|
|
837
874
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import io
|
|
2
2
|
import os
|
|
3
|
-
from typing import Any
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
from . import builder, util
|
|
6
6
|
from .builder import SpecTypeDefnObject
|
|
@@ -226,20 +226,20 @@ def _emit_endpoint(
|
|
|
226
226
|
|
|
227
227
|
if is_binary:
|
|
228
228
|
tsx_response_part = f"""import {{ {wrap_name} }} from "unc_base/api"
|
|
229
|
-
import {{ Arguments }} from "{type_path}"
|
|
229
|
+
import type {{ Arguments }} from "{type_path}"
|
|
230
230
|
|
|
231
231
|
export type {{ Arguments }}
|
|
232
232
|
"""
|
|
233
233
|
elif has_data and endpoint.has_attachment:
|
|
234
|
-
tsx_response_part = f"""import {{ {wrap_name}, AttachmentResponse }} from "unc_base/api"
|
|
235
|
-
import {{ Arguments, Data }} from "{type_path}"
|
|
234
|
+
tsx_response_part = f"""import {{ {wrap_name}, type AttachmentResponse }} from "unc_base/api"
|
|
235
|
+
import type {{ Arguments, Data }} from "{type_path}"
|
|
236
236
|
|
|
237
237
|
export type {{ Arguments, Data }}
|
|
238
238
|
export type Response = AttachmentResponse<Data>
|
|
239
239
|
"""
|
|
240
240
|
elif has_data:
|
|
241
|
-
tsx_response_part = f"""import {{ {wrap_name}, JsonResponse }} from "unc_base/api"
|
|
242
|
-
import {{ Arguments, Data }} from "{type_path}"
|
|
241
|
+
tsx_response_part = f"""import {{ {wrap_name}, type JsonResponse }} from "unc_base/api"
|
|
242
|
+
import type {{ Arguments, Data }} from "{type_path}"
|
|
243
243
|
|
|
244
244
|
export type {{ Arguments, Data }}
|
|
245
245
|
export type Response = JsonResponse<Data>
|
|
@@ -248,7 +248,7 @@ export type Response = JsonResponse<Data>
|
|
|
248
248
|
else:
|
|
249
249
|
assert has_deprecated_result
|
|
250
250
|
tsx_response_part = f"""import {{ {wrap_name} }} from "unc_base/api"
|
|
251
|
-
import {{ Arguments, DeprecatedResult }} from "{type_path}"
|
|
251
|
+
import type {{ Arguments, DeprecatedResult }} from "{type_path}"
|
|
252
252
|
|
|
253
253
|
export type {{ Arguments }}
|
|
254
254
|
export type Response = DeprecatedResult
|
|
@@ -278,7 +278,6 @@ export const apiCall = {wrap_call}(
|
|
|
278
278
|
if need_index:
|
|
279
279
|
with open(index_path, "a") as index:
|
|
280
280
|
print(f"Updated API Index {index_path}")
|
|
281
|
-
index.write("\n// eslint-disable-next-line import/first\n")
|
|
282
281
|
index.write(f'import * as {api_name} from "./{namespace.path[-1]}"\n\n')
|
|
283
282
|
index.write(f"export {{ {api_name} }}\n")
|
|
284
283
|
|
|
@@ -387,7 +386,7 @@ def refer_to(ctx: EmitTypescriptContext, stype: builder.SpecType) -> str:
|
|
|
387
386
|
|
|
388
387
|
def refer_to_impl(
|
|
389
388
|
ctx: EmitTypescriptContext, stype: builder.SpecType
|
|
390
|
-
) ->
|
|
389
|
+
) -> tuple[str, bool]:
|
|
391
390
|
"""
|
|
392
391
|
@return (string-specific, multiple-types)
|
|
393
392
|
"""
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import io
|
|
2
|
-
import typing
|
|
3
2
|
from dataclasses import dataclass, field
|
|
4
3
|
|
|
5
4
|
from . import builder, util
|
|
@@ -15,7 +14,7 @@ class EmitTypescriptContext:
|
|
|
15
14
|
config: TypeScriptConfig
|
|
16
15
|
out: io.StringIO
|
|
17
16
|
namespace: builder.SpecNamespace
|
|
18
|
-
namespaces:
|
|
17
|
+
namespaces: set[builder.SpecNamespace] = field(default_factory=set)
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
def ts_type_name(name: str) -> str:
|
pkgs/type_spec/load_types.py
CHANGED
pkgs/type_spec/open_api_util.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from enum import
|
|
2
|
+
from enum import StrEnum
|
|
3
3
|
from io import UnsupportedOperation
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
@@ -41,7 +41,7 @@ class OpenAPIRefType(OpenAPIType):
|
|
|
41
41
|
return {"$ref": self.source}
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
class OpenAPIPrimitive(
|
|
44
|
+
class OpenAPIPrimitive(StrEnum):
|
|
45
45
|
string = "string"
|
|
46
46
|
boolean = "boolean"
|
|
47
47
|
integer = "integer"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Types that type_spec will use in the emitted files.
|
|
3
3
|
"""
|
|
4
|
-
from typing import Union,
|
|
4
|
+
from typing import Union, Any, TYPE_CHECKING
|
|
5
|
+
from collections.abc import Mapping, Sequence
|
|
5
6
|
|
|
6
7
|
# These two are part of the core output, thus don't duplicate here
|
|
7
8
|
# from decimal import Decimal
|