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.

Files changed (81) hide show
  1. {UncountablePythonSDK-0.0.16.dist-info → UncountablePythonSDK-0.0.18.dist-info}/METADATA +14 -1
  2. {UncountablePythonSDK-0.0.16.dist-info → UncountablePythonSDK-0.0.18.dist-info}/RECORD +81 -33
  3. {UncountablePythonSDK-0.0.16.dist-info → UncountablePythonSDK-0.0.18.dist-info}/top_level.txt +1 -0
  4. docs/.gitignore +1 -0
  5. docs/conf.py +52 -0
  6. docs/index.md +13 -0
  7. docs/justfile +12 -0
  8. docs/quickstart.md +19 -0
  9. docs/requirements.txt +7 -0
  10. docs/static/favicons/android-chrome-192x192.png +0 -0
  11. docs/static/favicons/android-chrome-512x512.png +0 -0
  12. docs/static/favicons/apple-touch-icon.png +0 -0
  13. docs/static/favicons/browserconfig.xml +9 -0
  14. docs/static/favicons/favicon-16x16.png +0 -0
  15. docs/static/favicons/favicon-32x32.png +0 -0
  16. docs/static/favicons/manifest.json +18 -0
  17. docs/static/favicons/mstile-150x150.png +0 -0
  18. docs/static/favicons/safari-pinned-tab.svg +32 -0
  19. docs/static/logo_blue.png +0 -0
  20. examples/create_entity.py +23 -16
  21. pkgs/argument_parser/_is_enum.py +1 -1
  22. pkgs/argument_parser/argument_parser.py +26 -19
  23. pkgs/serialization/serial_class.py +3 -3
  24. pkgs/serialization_util/_get_type_for_serialization.py +1 -3
  25. pkgs/serialization_util/serialization_helpers.py +1 -3
  26. pkgs/strenum_compat/strenum_compat.py +1 -9
  27. pkgs/type_spec/actions_registry/__init__.py +0 -0
  28. pkgs/type_spec/actions_registry/__main__.py +114 -0
  29. pkgs/type_spec/actions_registry/emit_typescript.py +120 -0
  30. pkgs/type_spec/builder.py +14 -10
  31. pkgs/type_spec/config.py +3 -2
  32. pkgs/type_spec/emit_python.py +54 -17
  33. pkgs/type_spec/emit_typescript.py +8 -9
  34. pkgs/type_spec/emit_typescript_util.py +1 -2
  35. pkgs/type_spec/load_types.py +2 -1
  36. pkgs/type_spec/open_api_util.py +2 -2
  37. pkgs/type_spec/parts/base.py.prepart +2 -1
  38. pkgs/type_spec/util.py +9 -9
  39. pkgs/type_spec/value_spec/__main__.py +2 -2
  40. pkgs/type_spec/value_spec/emit_python.py +1 -0
  41. type_spec/external/api/batch/execute_batch_load_async.yaml +18 -0
  42. type_spec/external/api/chemical/convert_chemical_formats.yaml +33 -0
  43. type_spec/external/api/entity/create_entities.yaml +1 -1
  44. type_spec/external/api/entity/create_entity.yaml +1 -1
  45. type_spec/external/api/id_source/list_id_source.yaml +35 -0
  46. type_spec/external/api/id_source/match_id_source.yaml +32 -0
  47. type_spec/external/api/recipe_links/create_recipe_link.yaml +25 -0
  48. type_spec/external/api/recipes/associate_recipe_as_input.yaml +19 -0
  49. type_spec/external/api/recipes/associate_recipe_as_lot.yaml +19 -0
  50. type_spec/external/api/recipes/create_recipe.yaml +38 -0
  51. type_spec/external/api/recipes/get_recipes_data.yaml +21 -21
  52. type_spec/external/api/recipes/set_recipe_inputs.yaml +6 -0
  53. type_spec/external/api/recipes/set_recipe_metadata.yaml +19 -0
  54. type_spec/external/api/triggers/run_trigger.yaml +18 -0
  55. uncountable/core/client.py +13 -14
  56. uncountable/types/__init__.py +30 -0
  57. uncountable/types/api/batch/execute_batch_load_async.py +35 -0
  58. uncountable/types/api/chemical/__init__.py +1 -0
  59. uncountable/types/api/chemical/convert_chemical_formats.py +50 -0
  60. uncountable/types/api/entity/create_entities.py +1 -1
  61. uncountable/types/api/entity/create_entity.py +1 -1
  62. uncountable/types/api/id_source/__init__.py +1 -0
  63. uncountable/types/api/id_source/list_id_source.py +46 -0
  64. uncountable/types/api/id_source/match_id_source.py +48 -0
  65. uncountable/types/api/recipe_links/__init__.py +1 -0
  66. uncountable/types/api/recipe_links/create_recipe_link.py +39 -0
  67. uncountable/types/api/recipes/associate_recipe_as_input.py +35 -0
  68. uncountable/types/api/recipes/associate_recipe_as_lot.py +36 -0
  69. uncountable/types/api/recipes/create_recipe.py +43 -0
  70. uncountable/types/api/recipes/set_recipe_inputs.py +2 -0
  71. uncountable/types/api/recipes/set_recipe_metadata.py +36 -0
  72. uncountable/types/api/triggers/__init__.py +1 -0
  73. uncountable/types/api/triggers/run_trigger.py +36 -0
  74. uncountable/types/async_batch.py +45 -0
  75. uncountable/types/base.py +2 -1
  76. uncountable/types/chemical_structure.py +27 -0
  77. uncountable/types/client_base.py +404 -2
  78. uncountable/types/id_source.py +49 -0
  79. uncountable/types/identifier.py +54 -0
  80. uncountable/types/recipe_identifiers.py +62 -0
  81. {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 typing import Any, Callable, Optional, TypeVar, cast
5
-
6
- from pkgs.strenum_compat import StrEnum
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
 
@@ -1,11 +1,9 @@
1
1
  import dataclasses
2
2
  import datetime
3
3
  import functools
4
- from enum import Enum
4
+ from enum import Enum, StrEnum
5
5
  from typing import Any
6
6
 
7
- from pkgs.strenum_compat import StrEnum
8
-
9
7
 
10
8
  class SerializationType(StrEnum):
11
9
  NAMED_TUPLE = "NAMED_TUPLE"
@@ -1,13 +1,11 @@
1
1
  import datetime
2
2
  import enum
3
+ from collections.abc import Callable, Mapping, Sequence
3
4
  from decimal import Decimal
4
5
  from typing import (
5
6
  TYPE_CHECKING,
6
7
  Any,
7
- Callable,
8
- Mapping,
9
8
  Optional,
10
- Sequence,
11
9
  TypeVar,
12
10
  Union,
13
11
  )
@@ -1,9 +1 @@
1
- import sys
2
- from enum import Enum
3
-
4
- if sys.version_info >= (3, 11):
5
- from enum import StrEnum as StrEnum
6
- else:
7
-
8
- class StrEnum(str, Enum):
9
- pass
1
+ from enum import StrEnum as StrEnum
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, Dict, Optional
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 = Dict[Any, Any]
18
+ RawDict = dict[Any, Any]
19
19
 
20
20
 
21
- class PropertyExtant(str, Enum):
21
+ class PropertyExtant(StrEnum):
22
22
  required = "required"
23
23
  optional = "optional"
24
24
  missing = "missing"
25
25
 
26
26
 
27
- class PropertyConvertValue(str, Enum):
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(str, Enum):
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(str, Enum):
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(str, Enum):
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(str, Enum):
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(str, Enum):
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 Callable, Mapping, Self, Type, TypeVar
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: Type[_T], raw_value: ConfigValueType) -> _T:
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
 
@@ -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, Set
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: Set[builder.SpecNamespace] = field(default_factory=set)
29
- names: Set[str] = field(default_factory=set)
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: Set[str] = set()
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: Set[str]
470
- unconverted_values: Set[str]
471
- to_string_values: Set[str]
472
- parse_require: Set[str]
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: Set[str] = set()
484
- unconverted_values: Set[str] = set()
485
- to_string_values: Set[str] = set()
486
- parse_require: Set[str] = set()
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: Set[builder.SpecNamespace],
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, Type, Union\n")
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, Type[StrEnum]] = {\n")
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[\\\n{INDENT}")
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, Tuple
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
- ) -> Tuple[str, bool]:
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: typing.Set[builder.SpecNamespace] = field(default_factory=set)
17
+ namespaces: set[builder.SpecNamespace] = field(default_factory=set)
19
18
 
20
19
 
21
20
  def ts_type_name(name: str) -> str:
@@ -1,5 +1,6 @@
1
1
  import os
2
- from typing import Callable, Optional
2
+ from collections.abc import Callable
3
+ from typing import Optional
3
4
 
4
5
  import yaml
5
6
  from shelljob import fs
@@ -1,5 +1,5 @@
1
1
  from abc import ABC, abstractmethod
2
- from enum import Enum
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(str, Enum):
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, Mapping, Sequence, Any, TYPE_CHECKING
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