UncountablePythonSDK 0.0.73__py3-none-any.whl → 0.0.74__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.73.dist-info → UncountablePythonSDK-0.0.74.dist-info}/METADATA +1 -1
- {UncountablePythonSDK-0.0.73.dist-info → UncountablePythonSDK-0.0.74.dist-info}/RECORD +17 -17
- {UncountablePythonSDK-0.0.73.dist-info → UncountablePythonSDK-0.0.74.dist-info}/WHEEL +1 -1
- pkgs/argument_parser/__init__.py +1 -0
- pkgs/argument_parser/argument_parser.py +13 -1
- pkgs/serialization/serial_class.py +13 -0
- pkgs/type_spec/builder.py +68 -21
- pkgs/type_spec/emit_python.py +0 -3
- pkgs/type_spec/emit_typescript.py +31 -22
- pkgs/type_spec/emit_typescript_util.py +0 -2
- pkgs/type_spec/type_info/emit_type_info.py +7 -7
- pkgs/type_spec/util.py +1 -1
- uncountable/types/api/uploader/invoke_uploader.py +2 -1
- uncountable/types/async_batch_processor.py +4 -1
- uncountable/types/client_base.py +4 -1
- uncountable/types/entity_t.py +2 -0
- {UncountablePythonSDK-0.0.73.dist-info → UncountablePythonSDK-0.0.74.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: UncountablePythonSDK
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.74
|
|
4
4
|
Summary: Uncountable SDK
|
|
5
5
|
Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
|
|
6
6
|
Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
|
|
@@ -26,10 +26,10 @@ examples/integration-server/jobs/materials_auto/example_cron.py,sha256=7VVQ-UJsq
|
|
|
26
26
|
examples/integration-server/jobs/materials_auto/profile.yaml,sha256=MiqT9AHWoFz-rcpAHfiFTXuCP-18DaFipUaceati0-0,365
|
|
27
27
|
pkgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
28
|
pkgs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
-
pkgs/argument_parser/__init__.py,sha256=
|
|
29
|
+
pkgs/argument_parser/__init__.py,sha256=JRfZkC0-q6axr8F5_TKrjSprJ7d7chfcPvf-iMQqFg0,447
|
|
30
30
|
pkgs/argument_parser/_is_enum.py,sha256=Gw6jJa8nBwYGqXwwCZbSnWL8Rvr5alkg5lSVAqXtOZM,257
|
|
31
31
|
pkgs/argument_parser/_is_namedtuple.py,sha256=Rjc1bKanIPPogl3qG5JPBxglG1TqWYOo1nxxhBASQWY,265
|
|
32
|
-
pkgs/argument_parser/argument_parser.py,sha256=
|
|
32
|
+
pkgs/argument_parser/argument_parser.py,sha256=Z8lR_2L_N0zuxdOsK91D_9mjlsCcR_FJwtCLIfJz5oI,17713
|
|
33
33
|
pkgs/argument_parser/case_convert.py,sha256=NuJLJUJRbyVb6_Slen4uqaStEHbcOS1d-hBBfDrrw-c,605
|
|
34
34
|
pkgs/filesystem_utils/__init__.py,sha256=NSsQrUCoGISBCqCCyq6_583sYHTVEQeDjDO8hvZn3ag,1261
|
|
35
35
|
pkgs/filesystem_utils/_gdrive_session.py,sha256=GJuZYJq1W4QQ_7OLvZIMK99FgRq8FxJHg6cMUx9prtA,11077
|
|
@@ -41,7 +41,7 @@ pkgs/filesystem_utils/filesystem_session.py,sha256=BQ2Go8Mu9-GcnaWh2Pm4x7ugLVsre
|
|
|
41
41
|
pkgs/serialization/__init__.py,sha256=LifasRW0a50A3qRFmo2bf3FQ6TXhZWOTz2-CVTgPjcQ,753
|
|
42
42
|
pkgs/serialization/missing_sentry.py,sha256=aM_9KxbCk9dVvXvcOKgkIQBqFWvLhv8QlIUCiuFEXMo,806
|
|
43
43
|
pkgs/serialization/opaque_key.py,sha256=FIfXEE0DA1U8R_taFbQ1RCoTSgehrPjP06-qvo-GeNQ,177
|
|
44
|
-
pkgs/serialization/serial_class.py,sha256=
|
|
44
|
+
pkgs/serialization/serial_class.py,sha256=D7vSnfJw4rWEDFbDd07pxgzyfTFZT5SKeQEv4C1c4H0,6057
|
|
45
45
|
pkgs/serialization/serial_union.py,sha256=xpdeqCrRd0sNCaUwBQRzje6V40ndCbJpZrLX2K0d5xo,2741
|
|
46
46
|
pkgs/serialization/yaml.py,sha256=yoJtu7_ixnJV6uTxA_U1PpK5F_ixT08AKVh5ocyYwXM,1466
|
|
47
47
|
pkgs/serialization_util/__init__.py,sha256=MVKqHTUl2YnWZAFG9xCxu1SgmkQ5xPofrAGlYg6h7rI,330
|
|
@@ -52,25 +52,25 @@ pkgs/strenum_compat/__init__.py,sha256=wXRFeNvBm8RU6dy1PFJ5sRLgUIEeH_DVR95Sv5qpG
|
|
|
52
52
|
pkgs/strenum_compat/strenum_compat.py,sha256=uOUAgpYTjHs1MX8dG81jRlyTkt3KNbkV_25zp7xTX2s,36
|
|
53
53
|
pkgs/type_spec/__init__.py,sha256=h5DmJTca4QVV10sZR1x0-MlkZfuGYDfapR3zHvXfzto,19
|
|
54
54
|
pkgs/type_spec/__main__.py,sha256=5bJaX9Y_-FavP0qwzhk-z-V97UY7uaezJTa1zhO_HHQ,1048
|
|
55
|
-
pkgs/type_spec/builder.py,sha256=
|
|
55
|
+
pkgs/type_spec/builder.py,sha256=nuHdVNOmwbHbHV5_8nqtsrxOfzIII6jcQO7eLOljT4c,48856
|
|
56
56
|
pkgs/type_spec/config.py,sha256=ZUmPWCzTwjesAqlqeL1_E_yoIUZE_8g0kI2yXtbU0Zc,4811
|
|
57
57
|
pkgs/type_spec/emit_io_ts.py,sha256=U03sQBpgRqYOaMKrPCRnYb70YboiCgaZfseCXSzW5NY,5707
|
|
58
58
|
pkgs/type_spec/emit_open_api.py,sha256=5a0iAHBbgFD4wfKuyjPvxCYYHNTjKxEHA0aYjMGSqe4,24596
|
|
59
59
|
pkgs/type_spec/emit_open_api_util.py,sha256=x4GCiZSGdypJ9Qtm6I5W_3UvwdJyMs8_OGhJ8_THznA,2401
|
|
60
|
-
pkgs/type_spec/emit_python.py,sha256=
|
|
61
|
-
pkgs/type_spec/emit_typescript.py,sha256=
|
|
62
|
-
pkgs/type_spec/emit_typescript_util.py,sha256=
|
|
60
|
+
pkgs/type_spec/emit_python.py,sha256=eBct7PMYgcv35POo2JU089lLggPrgLfTOrKpqAukn1E,47370
|
|
61
|
+
pkgs/type_spec/emit_typescript.py,sha256=w9DUpksc4QP0CatUU9NYSZN4IBNNXVXkMnKMCFQmL58,18274
|
|
62
|
+
pkgs/type_spec/emit_typescript_util.py,sha256=StCDbJ5mU23MBb2LGu847yJN2fuiogjoQqZu6q3E6FY,797
|
|
63
63
|
pkgs/type_spec/load_types.py,sha256=vO8VLI7aTKzzHQIla-WO-5Z_mfTuwUqH4ZSKN9E9n5U,3688
|
|
64
64
|
pkgs/type_spec/open_api_util.py,sha256=IGh-_snGPST_P_8FdYtO8MTEa9PUxRW6Rzg9X9EgQik,7114
|
|
65
65
|
pkgs/type_spec/test.py,sha256=4ueujBq-pEgnX3Z69HyPmD-bullFXmpixcpVzfOkhP4,489
|
|
66
|
-
pkgs/type_spec/util.py,sha256=
|
|
66
|
+
pkgs/type_spec/util.py,sha256=79SLJsSPVnBe2_3CTF6J-7-QD9nRr6o8MKvfjyx53eI,4864
|
|
67
67
|
pkgs/type_spec/actions_registry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
68
|
pkgs/type_spec/actions_registry/__main__.py,sha256=JGwKxcAmrQdbpVR2vwknoimN1Q-r5h4SADw1cYLYzgk,4331
|
|
69
69
|
pkgs/type_spec/actions_registry/emit_typescript.py,sha256=Z1ZM4zOw26tvLspvW6Emg79-jxjhNBse-8yaionbmeo,6066
|
|
70
70
|
pkgs/type_spec/parts/base.py.prepart,sha256=wGNoDyQnLolHRZGRwHQX5TrPfKnu558NXCocYvqyroc,2174
|
|
71
71
|
pkgs/type_spec/parts/base.ts.prepart,sha256=2FJJvpg2olCcavxj0nbYWdwKl6KeScour2JjSvN42l8,1001
|
|
72
72
|
pkgs/type_spec/type_info/__main__.py,sha256=pmVjVqXyVh8vKTNCTFgz80Sg74C5BKToP3E6GS-X_So,857
|
|
73
|
-
pkgs/type_spec/type_info/emit_type_info.py,sha256=
|
|
73
|
+
pkgs/type_spec/type_info/emit_type_info.py,sha256=C4Rq5z22c3IJTyQriNkQWgGV7I3ZgTDjwKm_JM_sOYI,13362
|
|
74
74
|
pkgs/type_spec/value_spec/__init__.py,sha256=Z-grlcZtxAfEXhPHsK0nD7PFLGsv4eqvunaPN7_TA84,83
|
|
75
75
|
pkgs/type_spec/value_spec/__main__.py,sha256=6bzP85p_Cm4bPp5tXz8D_4p64wMn5SKsXC7SqSZquYc,8318
|
|
76
76
|
pkgs/type_spec/value_spec/convert_type.py,sha256=Tg5YsYOwvmf_EqbCAtCmqy3-dud8OwdbEOzAaRN7cCs,2286
|
|
@@ -124,7 +124,7 @@ uncountable/integration/secret_retrieval/retrieve_secret.py,sha256=eoPWbkUtCn_63
|
|
|
124
124
|
uncountable/integration/webhook_server/entrypoint.py,sha256=hgbEtdVo3QU3odlHSygxmrsxR9g7rgU0yKt-o9nVAHE,5686
|
|
125
125
|
uncountable/types/__init__.py,sha256=KSsSEBnGhn88NPex5q9MZtY4kj8PRqVTbaKtko4hxUU,8561
|
|
126
126
|
uncountable/types/async_batch.py,sha256=_OhT25_dEVts_z_n1kqfJH3xlZg3btLqR6TNkfFLlXE,609
|
|
127
|
-
uncountable/types/async_batch_processor.py,sha256=
|
|
127
|
+
uncountable/types/async_batch_processor.py,sha256=esKBP56RiRH-VjAFBr8wgfcgKsRkUfiLBmQmYGx4XXY,11462
|
|
128
128
|
uncountable/types/async_batch_t.py,sha256=CZ-rltFUiKVowvL5BhMfWaFxgf-Z0KPsghvjsg-PweY,2493
|
|
129
129
|
uncountable/types/base.py,sha256=xVSjWvA_fUUnkCg83EjoYEFvAfmskinKFMeYFOxNc9E,359
|
|
130
130
|
uncountable/types/base_t.py,sha256=XXjZXexx0xWFUxMMhW8i9nIL6n8dsZVsHwdgnhZ0zJ4,2714
|
|
@@ -132,13 +132,13 @@ uncountable/types/calculations.py,sha256=FFO_D3BbKoGDZnqWvTKpW4KF359i2vrKjpdFCLY
|
|
|
132
132
|
uncountable/types/calculations_t.py,sha256=157qD0VqijD5kNDF5BRsfGli3WaPGnNjoo2o2CPX-Ik,669
|
|
133
133
|
uncountable/types/chemical_structure.py,sha256=E-LnikTFDoVQ1b2zKaVUIO_PAKm-7aZZYJi8I8SDSic,302
|
|
134
134
|
uncountable/types/chemical_structure_t.py,sha256=zDJ6WkeT3YwWZRZT21znQn2ZYelv3L7yv7kJiGoNZCw,824
|
|
135
|
-
uncountable/types/client_base.py,sha256=
|
|
135
|
+
uncountable/types/client_base.py,sha256=16W0EnH7kyy_sRL_fNn4NBvNhE8NCmmrSad-grKhLus,67489
|
|
136
136
|
uncountable/types/client_config.py,sha256=4h5Liko9uKCo9_0gdbPhoK6Jr2Kv7tioLiQ8iKeq-_4,301
|
|
137
137
|
uncountable/types/client_config_t.py,sha256=6dStfR0IEHiPW8f9_aF3DD_tHmXXw2rEVrgpebzq8Fg,747
|
|
138
138
|
uncountable/types/curves.py,sha256=W6uMpG5SyW1MS82szNpxkFEn1MnxNpBFyFbQb2Ysfng,366
|
|
139
139
|
uncountable/types/curves_t.py,sha256=lKhRM-2cZ_sFaW7pa_I_Ipz_pJhm3_yTFehRXI79pKk,1416
|
|
140
140
|
uncountable/types/entity.py,sha256=3XhLteFDRDZvHejDuYh-KvB65hpwrBygljFfiUcOAM8,315
|
|
141
|
-
uncountable/types/entity_t.py,sha256=
|
|
141
|
+
uncountable/types/entity_t.py,sha256=8OkFVgvrItdA1ysyWB21mLL85JTPdcdzAmb6CNBUVI0,15003
|
|
142
142
|
uncountable/types/experiment_groups.py,sha256=_0OXcPzSAbkE-rfKt5tPx178YJ4pcEKZvrCxUHgDnvw,309
|
|
143
143
|
uncountable/types/experiment_groups_t.py,sha256=qEs8YW0eJOJ_sCOObT5v9QRx9wsjLYpJqJhCJXa-vNA,721
|
|
144
144
|
uncountable/types/field_values.py,sha256=uuIWX-xmfvcinYPdfkWJeb56zzQY01mc9rmotMPMh24,503
|
|
@@ -276,8 +276,8 @@ uncountable/types/api/recipes/unlock_recipes.py,sha256=RaC5N5rz6f3FAIaQM3NgLuXEM
|
|
|
276
276
|
uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
277
277
|
uncountable/types/api/triggers/run_trigger.py,sha256=-oZgPyn43xEKSCs81DVNzwaYMCdRJxbM9GY6fsqKwf4,1090
|
|
278
278
|
uncountable/types/api/uploader/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
279
|
-
uncountable/types/api/uploader/invoke_uploader.py,sha256=
|
|
280
|
-
UncountablePythonSDK-0.0.
|
|
281
|
-
UncountablePythonSDK-0.0.
|
|
282
|
-
UncountablePythonSDK-0.0.
|
|
283
|
-
UncountablePythonSDK-0.0.
|
|
279
|
+
uncountable/types/api/uploader/invoke_uploader.py,sha256=6mwVG136oLp9JcbB2I-kZnrcm3aeZzYZB-SFjEImY2o,1314
|
|
280
|
+
UncountablePythonSDK-0.0.74.dist-info/METADATA,sha256=cvY7ALGHYsY6rqK3qLdaXGE_8joz1ouiGFKtbPaOsFw,2051
|
|
281
|
+
UncountablePythonSDK-0.0.74.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
|
282
|
+
UncountablePythonSDK-0.0.74.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
|
|
283
|
+
UncountablePythonSDK-0.0.74.dist-info/RECORD,,
|
pkgs/argument_parser/__init__.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from .argument_parser import CachedParser as CachedParser
|
|
2
|
+
from .argument_parser import ParserFunction as ParserFunction
|
|
2
3
|
from .argument_parser import ParserOptions as ParserOptions
|
|
3
4
|
from .argument_parser import build_parser as build_parser
|
|
4
5
|
from .case_convert import camel_to_snake_case as camel_to_snake_case
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import dataclasses
|
|
2
|
+
import math
|
|
2
3
|
import types
|
|
3
4
|
import typing
|
|
4
5
|
from collections import defaultdict
|
|
@@ -299,7 +300,18 @@ def _build_parser_inner(
|
|
|
299
300
|
|
|
300
301
|
return parse_str
|
|
301
302
|
|
|
302
|
-
if parsed_type in (float,
|
|
303
|
+
if parsed_type in (float, Decimal):
|
|
304
|
+
|
|
305
|
+
def parse_as_numeric_type(value: typing.Any) -> T:
|
|
306
|
+
numeric_value: Decimal | float = parsed_type(value) # type: ignore
|
|
307
|
+
if math.isnan(numeric_value):
|
|
308
|
+
raise ValueError(f"Invalid numeric value: {numeric_value}")
|
|
309
|
+
|
|
310
|
+
return numeric_value # type: ignore
|
|
311
|
+
|
|
312
|
+
return parse_as_numeric_type
|
|
313
|
+
|
|
314
|
+
if parsed_type in (dict, bool) or is_string_enum_class(parsed_type):
|
|
303
315
|
return lambda value: parsed_type(value) # type: ignore
|
|
304
316
|
|
|
305
317
|
if parsed_type is MissingSentryType:
|
|
@@ -15,6 +15,10 @@ class _SerialClassData:
|
|
|
15
15
|
to_string_values: set[str] = dataclasses.field(default_factory=set)
|
|
16
16
|
parse_require: set[str] = dataclasses.field(default_factory=set)
|
|
17
17
|
named_type_path: Optional[str] = None
|
|
18
|
+
# Tracks if this data was provided as a decorator to the type.
|
|
19
|
+
# This is used to track "proper types" which are appropriate
|
|
20
|
+
# for serialization and/or dynamic discovery
|
|
21
|
+
from_decorator: bool = False
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
EMPTY_SERIAL_CLASS_DATA = _SerialClassData()
|
|
@@ -58,6 +62,7 @@ def serial_class(
|
|
|
58
62
|
to_string_values=to_string_values or set(),
|
|
59
63
|
parse_require=parse_require or set(),
|
|
60
64
|
named_type_path=named_type_path,
|
|
65
|
+
from_decorator=True,
|
|
61
66
|
)
|
|
62
67
|
return orig_class
|
|
63
68
|
|
|
@@ -83,6 +88,14 @@ class SerialClassDataInspector:
|
|
|
83
88
|
def has_parse_require(self, key: str) -> bool:
|
|
84
89
|
return key in self.current.parse_require
|
|
85
90
|
|
|
91
|
+
@property
|
|
92
|
+
def from_decorator(self) -> bool:
|
|
93
|
+
return self.current.from_decorator
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def named_type_path(self) -> Optional[str]:
|
|
97
|
+
return self.current.named_type_path
|
|
98
|
+
|
|
86
99
|
|
|
87
100
|
def _get_merged_serial_class_data(type_class: type[Any]) -> _SerialClassData | None:
|
|
88
101
|
base_class_data = (
|
pkgs/type_spec/builder.py
CHANGED
|
@@ -307,6 +307,9 @@ class SpecTypeDefn(SpecType):
|
|
|
307
307
|
def is_base_type(self, type_: BaseTypeName) -> bool:
|
|
308
308
|
return self.is_base and self.name == type_
|
|
309
309
|
|
|
310
|
+
def can_process(self, builder: SpecBuilder, data: RawDict) -> bool:
|
|
311
|
+
return True
|
|
312
|
+
|
|
310
313
|
@abc.abstractmethod
|
|
311
314
|
def process(self, builder: SpecBuilder, data: RawDict) -> None: ...
|
|
312
315
|
|
|
@@ -666,15 +669,30 @@ class SpecTypeDefnStringEnum(SpecTypeDefn):
|
|
|
666
669
|
self.desc: str | None = None
|
|
667
670
|
self.sql_type_name: Optional[str] = None
|
|
668
671
|
self.emit_id_source = False
|
|
672
|
+
self.source_enums: list[SpecType] = []
|
|
673
|
+
|
|
674
|
+
def can_process(self, builder: SpecBuilder, data: dict[Any, Any]) -> bool:
|
|
675
|
+
source_enums = data.get("source_enums")
|
|
676
|
+
try:
|
|
677
|
+
for sub_type_str in source_enums or []:
|
|
678
|
+
sub_type = builder.parse_type(self.namespace, sub_type_str)
|
|
679
|
+
assert isinstance(sub_type, SpecTypeDefnStringEnum)
|
|
680
|
+
assert len(sub_type.values) > 0
|
|
681
|
+
except AssertionError:
|
|
682
|
+
return False
|
|
683
|
+
return super().can_process(builder, data)
|
|
669
684
|
|
|
670
685
|
def process(self, builder: SpecBuilder, data: RawDict) -> None:
|
|
671
686
|
super().base_process(
|
|
672
|
-
builder,
|
|
687
|
+
builder,
|
|
688
|
+
data,
|
|
689
|
+
["type", "desc", "values", "name_case", "sql", "emit", "source_enums"],
|
|
673
690
|
)
|
|
674
691
|
self.name_case = NameCase(data.get("name_case", "convert"))
|
|
675
692
|
self.values = {}
|
|
676
|
-
data_values = data
|
|
693
|
+
data_values = data.get("values")
|
|
677
694
|
self.desc = data.get("desc", None)
|
|
695
|
+
source_enums = data.get("source_enums", None)
|
|
678
696
|
if isinstance(data_values, dict):
|
|
679
697
|
for name, value in data_values.items():
|
|
680
698
|
builder.push_where(name)
|
|
@@ -717,7 +735,8 @@ class SpecTypeDefnStringEnum(SpecTypeDefn):
|
|
|
717
735
|
)
|
|
718
736
|
self.values[value] = StringEnumEntry(name=value, value=value)
|
|
719
737
|
else:
|
|
720
|
-
|
|
738
|
+
if source_enums is None or data_values is not None:
|
|
739
|
+
raise Exception("unsupported values type")
|
|
721
740
|
|
|
722
741
|
sql_data = data.get("sql")
|
|
723
742
|
if sql_data is not None:
|
|
@@ -739,9 +758,18 @@ class SpecTypeDefnStringEnum(SpecTypeDefn):
|
|
|
739
758
|
builder.ensure(
|
|
740
759
|
entry.label is not None, f"need-label-for-id-source:{entry.name}"
|
|
741
760
|
)
|
|
761
|
+
for sub_type_str in source_enums or []:
|
|
762
|
+
sub_type = builder.parse_type(self.namespace, sub_type_str)
|
|
763
|
+
self.source_enums.append(sub_type)
|
|
764
|
+
|
|
765
|
+
for sub_type in self.source_enums:
|
|
766
|
+
builder.push_where(sub_type.name)
|
|
767
|
+
if isinstance(sub_type, SpecTypeDefnStringEnum):
|
|
768
|
+
self.values.update(sub_type.values)
|
|
769
|
+
builder.pop_where()
|
|
742
770
|
|
|
743
771
|
def get_referenced_types(self) -> list[SpecType]:
|
|
744
|
-
return
|
|
772
|
+
return self.source_enums
|
|
745
773
|
|
|
746
774
|
|
|
747
775
|
TOKEN_ENDPOINT = "$endpoint"
|
|
@@ -1122,28 +1150,41 @@ class SpecNamespace:
|
|
|
1122
1150
|
Complete the definition of each type.
|
|
1123
1151
|
"""
|
|
1124
1152
|
builder.push_where(self.name)
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1153
|
+
items_to_process: list[NameDataPair] = [
|
|
1154
|
+
NameDataPair(full_name=full_name, data=defn)
|
|
1155
|
+
for full_name, defn in data.items()
|
|
1156
|
+
]
|
|
1157
|
+
while len(items_to_process) > 0:
|
|
1158
|
+
deferred_items: list[NameDataPair] = []
|
|
1159
|
+
for item in items_to_process:
|
|
1160
|
+
full_name = item.full_name
|
|
1161
|
+
defn = item.data
|
|
1162
|
+
parsed_name = parse_type_str(full_name)[0]
|
|
1163
|
+
name = parsed_name.name
|
|
1164
|
+
|
|
1165
|
+
if name in [TOKEN_EMIT_IO_TS, TOKEN_EMIT_TYPE_INFO, TOKEN_IMPORT]:
|
|
1166
|
+
continue
|
|
1128
1167
|
|
|
1129
|
-
|
|
1130
|
-
continue
|
|
1168
|
+
builder.push_where(name)
|
|
1131
1169
|
|
|
1132
|
-
|
|
1170
|
+
if "value" in defn:
|
|
1171
|
+
spec_constant = self.constants[name]
|
|
1172
|
+
spec_constant.process(builder, defn)
|
|
1133
1173
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1174
|
+
elif name == TOKEN_ENDPOINT:
|
|
1175
|
+
assert self.endpoint
|
|
1176
|
+
self.endpoint.process(builder, defn)
|
|
1137
1177
|
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
spec_type.process(builder, defn)
|
|
1178
|
+
else:
|
|
1179
|
+
spec_type = self.types[name]
|
|
1180
|
+
if spec_type.can_process(builder, defn):
|
|
1181
|
+
spec_type.process(builder, defn)
|
|
1182
|
+
else:
|
|
1183
|
+
deferred_items.append(item)
|
|
1145
1184
|
|
|
1146
|
-
|
|
1185
|
+
builder.pop_where()
|
|
1186
|
+
assert len(deferred_items) < len(items_to_process)
|
|
1187
|
+
items_to_process = [deferred for deferred in deferred_items]
|
|
1147
1188
|
|
|
1148
1189
|
builder.pop_where()
|
|
1149
1190
|
|
|
@@ -1158,6 +1199,12 @@ class NamespaceDataPair:
|
|
|
1158
1199
|
data: RawDict
|
|
1159
1200
|
|
|
1160
1201
|
|
|
1202
|
+
@dataclass(kw_only=True)
|
|
1203
|
+
class NameDataPair:
|
|
1204
|
+
full_name: str
|
|
1205
|
+
data: RawDict
|
|
1206
|
+
|
|
1207
|
+
|
|
1161
1208
|
class SpecBuilder:
|
|
1162
1209
|
def __init__(self, *, api_endpoints: dict[str, str], top_namespace: str) -> None:
|
|
1163
1210
|
self.top_namespace = top_namespace
|
pkgs/type_spec/emit_python.py
CHANGED
|
@@ -44,7 +44,6 @@ class TrackingContext:
|
|
|
44
44
|
use_enum: bool = False
|
|
45
45
|
use_serial_string_enum: bool = False
|
|
46
46
|
use_dataclass: bool = False
|
|
47
|
-
use_serial_class: bool = False
|
|
48
47
|
use_serial_union: bool = False
|
|
49
48
|
use_missing: bool = False
|
|
50
49
|
use_opaque_key: bool = False
|
|
@@ -223,7 +222,6 @@ def _emit_types_imports(*, out: io.StringIO, ctx: Context) -> None:
|
|
|
223
222
|
out.write("from pkgs.strenum_compat import StrEnum\n")
|
|
224
223
|
if ctx.use_dataclass:
|
|
225
224
|
out.write("import dataclasses\n")
|
|
226
|
-
if ctx.use_serial_class:
|
|
227
225
|
out.write("from pkgs.serialization import serial_class\n")
|
|
228
226
|
if ctx.use_serial_union:
|
|
229
227
|
out.write("from pkgs.serialization import serial_union_annotation\n")
|
|
@@ -834,7 +832,6 @@ def _emit_type(ctx: Context, stype: builder.SpecType) -> None:
|
|
|
834
832
|
_emit_generic(ctx, stype.get_generic())
|
|
835
833
|
|
|
836
834
|
# Emit serial_class decorator
|
|
837
|
-
ctx.use_serial_class = True
|
|
838
835
|
ctx.out.write("@serial_class(\n")
|
|
839
836
|
ctx.out.write(
|
|
840
837
|
f"{INDENT}named_type_path={util.encode_common_string(_named_type_path(ctx, stype))},\n"
|
|
@@ -82,6 +82,25 @@ def emit_typescript(builder: builder.SpecBuilder, config: TypeScriptConfig) -> N
|
|
|
82
82
|
_emit_id_source(builder, config)
|
|
83
83
|
|
|
84
84
|
|
|
85
|
+
def emit_namespace_imports_ts(
|
|
86
|
+
namespaces: set[builder.SpecNamespace],
|
|
87
|
+
out: io.StringIO,
|
|
88
|
+
current_namespace: builder.SpecNamespace,
|
|
89
|
+
) -> None:
|
|
90
|
+
for ns in sorted(
|
|
91
|
+
namespaces,
|
|
92
|
+
key=lambda name: _resolve_namespace_name(name),
|
|
93
|
+
):
|
|
94
|
+
import_as = resolve_namespace_ref(ns)
|
|
95
|
+
import_path = (
|
|
96
|
+
"./"
|
|
97
|
+
if len(current_namespace.path) == 1
|
|
98
|
+
else "../" * (len(current_namespace.path) - 1)
|
|
99
|
+
)
|
|
100
|
+
import_from = f"{import_path}{_resolve_namespace_name(ns)}"
|
|
101
|
+
out.write(f'import * as {import_as} from "{import_from}"\n') # noqa: E501
|
|
102
|
+
|
|
103
|
+
|
|
85
104
|
def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
|
|
86
105
|
index_out = io.StringIO()
|
|
87
106
|
index_out.write(MODIFY_NOTICE)
|
|
@@ -92,11 +111,9 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
|
|
|
92
111
|
builder.namespaces.values(),
|
|
93
112
|
key=lambda ns: _resolve_namespace_name(ns),
|
|
94
113
|
):
|
|
95
|
-
ctx = EmitTypescriptContext(
|
|
96
|
-
out=io.StringIO(), namespace=namespace, config=config
|
|
97
|
-
)
|
|
114
|
+
ctx = EmitTypescriptContext(out=io.StringIO(), namespace=namespace)
|
|
98
115
|
|
|
99
|
-
_emit_namespace(ctx, namespace)
|
|
116
|
+
_emit_namespace(ctx, config, namespace)
|
|
100
117
|
|
|
101
118
|
prepart = builder.preparts["typescript"].get(namespace.name)
|
|
102
119
|
part = builder.parts["typescript"].get(namespace.name)
|
|
@@ -123,16 +140,7 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
|
|
|
123
140
|
full.write(f"// === END section from {namespace.name}.ts.prepart ===\n")
|
|
124
141
|
full.write("\n")
|
|
125
142
|
|
|
126
|
-
|
|
127
|
-
ctx.namespaces,
|
|
128
|
-
key=lambda name: _resolve_namespace_name(name),
|
|
129
|
-
):
|
|
130
|
-
import_as = resolve_namespace_ref(ns)
|
|
131
|
-
import_path = (
|
|
132
|
-
"./" if len(namespace.path) == 1 else "../" * (len(namespace.path) - 1)
|
|
133
|
-
)
|
|
134
|
-
import_from = f"{import_path}{_resolve_namespace_name(ns)}"
|
|
135
|
-
full.write(f'import * as {import_as} from "{import_from}"\n') # noqa: E501
|
|
143
|
+
emit_namespace_imports_ts(ctx.namespaces, out=full, current_namespace=namespace)
|
|
136
144
|
if namespace.emit_io_ts:
|
|
137
145
|
full.write("import * as IO from 'io-ts';")
|
|
138
146
|
full.write(ctx.out.getvalue())
|
|
@@ -164,23 +172,26 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
|
|
|
164
172
|
|
|
165
173
|
|
|
166
174
|
def _emit_namespace(
|
|
167
|
-
ctx: EmitTypescriptContext,
|
|
175
|
+
ctx: EmitTypescriptContext,
|
|
176
|
+
config: TypeScriptConfig,
|
|
177
|
+
namespace: builder.SpecNamespace,
|
|
168
178
|
) -> None:
|
|
169
179
|
for stype in namespace.types.values():
|
|
170
180
|
if namespace.emit_io_ts:
|
|
171
181
|
emit_type_io_ts(ctx, stype, namespace.derive_types_from_io_ts)
|
|
172
182
|
if not namespace.emit_io_ts or not namespace.derive_types_from_io_ts:
|
|
173
|
-
|
|
183
|
+
emit_type_ts(ctx, stype)
|
|
174
184
|
|
|
175
185
|
for sconst in namespace.constants.values():
|
|
176
186
|
_emit_constant(ctx, sconst)
|
|
177
187
|
|
|
178
188
|
if namespace.endpoint is not None:
|
|
179
|
-
_emit_endpoint(ctx, namespace, namespace.endpoint)
|
|
189
|
+
_emit_endpoint(ctx, config, namespace, namespace.endpoint)
|
|
180
190
|
|
|
181
191
|
|
|
182
192
|
def _emit_endpoint(
|
|
183
193
|
ctx: EmitTypescriptContext,
|
|
194
|
+
config: TypeScriptConfig,
|
|
184
195
|
namespace: builder.SpecNamespace,
|
|
185
196
|
endpoint: builder.SpecEndpoint,
|
|
186
197
|
) -> None:
|
|
@@ -265,14 +276,12 @@ export const apiCall = {wrap_call}(
|
|
|
265
276
|
)
|
|
266
277
|
{data_loader_body}"""
|
|
267
278
|
|
|
268
|
-
output = f"{
|
|
279
|
+
output = f"{config.routes_output}/{"/".join(namespace.path)}.tsx"
|
|
269
280
|
util.rewrite_file(output, tsx_api)
|
|
270
281
|
|
|
271
282
|
# Hacky index support, until enough is migrated to regen entirely
|
|
272
283
|
# Emits the import into the UI API index file
|
|
273
|
-
index_path = (
|
|
274
|
-
f"{ctx.config.routes_output}/{"/".join(namespace.path[0:-1])}/index.tsx"
|
|
275
|
-
)
|
|
284
|
+
index_path = f"{config.routes_output}/{"/".join(namespace.path[0:-1])}/index.tsx"
|
|
276
285
|
api_name = f"Api{ts_type_name(namespace.path[0 - 1])}"
|
|
277
286
|
if os.path.exists(index_path):
|
|
278
287
|
with open(index_path) as index:
|
|
@@ -288,7 +297,7 @@ export const apiCall = {wrap_call}(
|
|
|
288
297
|
index.write(f"export {{ {api_name} }}\n")
|
|
289
298
|
|
|
290
299
|
|
|
291
|
-
def
|
|
300
|
+
def emit_type_ts(ctx: EmitTypescriptContext, stype: builder.SpecType) -> None:
|
|
292
301
|
if not isinstance(stype, builder.SpecTypeDefn):
|
|
293
302
|
return
|
|
294
303
|
|
|
@@ -2,7 +2,6 @@ import io
|
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
3
|
|
|
4
4
|
from . import builder, util
|
|
5
|
-
from .config import TypeScriptConfig
|
|
6
5
|
|
|
7
6
|
INDENT = " "
|
|
8
7
|
|
|
@@ -11,7 +10,6 @@ MODIFY_NOTICE = "// DO NOT MODIFY -- This file is generated by type_spec\n"
|
|
|
11
10
|
|
|
12
11
|
@dataclass(kw_only=True)
|
|
13
12
|
class EmitTypescriptContext:
|
|
14
|
-
config: TypeScriptConfig
|
|
15
13
|
out: io.StringIO
|
|
16
14
|
namespace: builder.SpecNamespace
|
|
17
15
|
namespaces: set[builder.SpecNamespace] = field(default_factory=set)
|
|
@@ -5,7 +5,7 @@ import io
|
|
|
5
5
|
import json
|
|
6
6
|
from typing import Any, Optional, Union, cast
|
|
7
7
|
|
|
8
|
-
from main.base.types import data_t
|
|
8
|
+
from main.base.types import data_t, type_info_t
|
|
9
9
|
from main.base.types.base_t import PureJsonValue
|
|
10
10
|
from pkgs.argument_parser import CachedParser
|
|
11
11
|
from pkgs.serialization_util import (
|
|
@@ -17,7 +17,7 @@ from .. import builder, util
|
|
|
17
17
|
from ..emit_typescript_util import MODIFY_NOTICE, ts_name
|
|
18
18
|
from ..value_spec import convert_to_value_spec_type
|
|
19
19
|
|
|
20
|
-
ext_info_parser = CachedParser(
|
|
20
|
+
ext_info_parser = CachedParser(type_info_t.ExtInfo, strict_property_parsing=True)
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def type_path_of(stype: builder.SpecType) -> object: # NamePath
|
|
@@ -174,7 +174,7 @@ class InheritablePropertyParts:
|
|
|
174
174
|
|
|
175
175
|
label: Optional[str] = None
|
|
176
176
|
desc: Optional[str] = None
|
|
177
|
-
ext_info: Optional[
|
|
177
|
+
ext_info: Optional[type_info_t.ExtInfo] = None
|
|
178
178
|
|
|
179
179
|
|
|
180
180
|
def _extract_inheritable_property_parts(
|
|
@@ -201,7 +201,7 @@ def _extract_inheritable_property_parts(
|
|
|
201
201
|
elif base_parts.ext_info is None:
|
|
202
202
|
ext_info = local_ext_info
|
|
203
203
|
else:
|
|
204
|
-
ext_info =
|
|
204
|
+
ext_info = type_info_t.ExtInfo(
|
|
205
205
|
**(local_ext_info.__dict__ | base_parts.ext_info.__dict__)
|
|
206
206
|
)
|
|
207
207
|
|
|
@@ -214,7 +214,7 @@ ALL_FIELDS_GROUP = "*all_fields"
|
|
|
214
214
|
|
|
215
215
|
def _extract_and_validate_layout(
|
|
216
216
|
stype: builder.SpecTypeDefnObject,
|
|
217
|
-
ext_info:
|
|
217
|
+
ext_info: type_info_t.ExtInfo,
|
|
218
218
|
base_layout: ExtInfoLayout | None,
|
|
219
219
|
) -> ExtInfoLayout:
|
|
220
220
|
"""
|
|
@@ -264,7 +264,7 @@ def _extract_and_validate_layout(
|
|
|
264
264
|
|
|
265
265
|
def _validate_type_ext_info(
|
|
266
266
|
stype: builder.SpecTypeDefnObject,
|
|
267
|
-
) -> tuple[ExtInfoLayout | None, Optional[
|
|
267
|
+
) -> tuple[ExtInfoLayout | None, Optional[type_info_t.ExtInfo]]:
|
|
268
268
|
ext_info = _parse_ext_info(stype.ext_info)
|
|
269
269
|
if ext_info is None:
|
|
270
270
|
return None, None
|
|
@@ -364,7 +364,7 @@ def _build_map_type(
|
|
|
364
364
|
return None
|
|
365
365
|
|
|
366
366
|
|
|
367
|
-
def _parse_ext_info(in_ext: Any) -> Optional[
|
|
367
|
+
def _parse_ext_info(in_ext: Any) -> Optional[type_info_t.ExtInfo]:
|
|
368
368
|
if in_ext is None:
|
|
369
369
|
return None
|
|
370
370
|
assert isinstance(in_ext, dict)
|
pkgs/type_spec/util.py
CHANGED
|
@@ -159,7 +159,7 @@ def is_valid_property_name(name: str) -> bool:
|
|
|
159
159
|
def check_fields(data: dict[str, T], allowed: list[str]) -> None:
|
|
160
160
|
for key in data:
|
|
161
161
|
if key not in allowed:
|
|
162
|
-
raise Exception(f"unexpected-field: {key}")
|
|
162
|
+
raise Exception(f"unexpected-field: {key}. Allowed: {allowed}")
|
|
163
163
|
|
|
164
164
|
|
|
165
165
|
def split_any_name(name: str) -> list[str]:
|
|
@@ -31,9 +31,10 @@ ENDPOINT_PATH = "api/external/uploader/invoke_uploader"
|
|
|
31
31
|
)
|
|
32
32
|
@dataclasses.dataclass(kw_only=True)
|
|
33
33
|
class Arguments:
|
|
34
|
-
file_id: base_t.ObjectId
|
|
35
34
|
uploader_key: identifier_t.IdentifierKey
|
|
36
35
|
destination: generic_upload_t.UploadDestination
|
|
36
|
+
file_id: typing.Optional[base_t.ObjectId] = None
|
|
37
|
+
file_ids: typing.Optional[list[base_t.ObjectId]] = None
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
# DO NOT MODIFY -- This file is generated by type_spec
|
|
@@ -233,17 +233,20 @@ class AsyncBatchProcessorBase(ABC):
|
|
|
233
233
|
def invoke_uploader(
|
|
234
234
|
self,
|
|
235
235
|
*,
|
|
236
|
-
file_id: base_t.ObjectId,
|
|
237
236
|
uploader_key: identifier_t.IdentifierKey,
|
|
238
237
|
destination: generic_upload_t.UploadDestination,
|
|
238
|
+
file_id: typing.Optional[base_t.ObjectId] = None,
|
|
239
|
+
file_ids: typing.Optional[list[base_t.ObjectId]] = None,
|
|
239
240
|
depends_on: typing.Optional[list[str]] = None,
|
|
240
241
|
) -> async_batch_t.QueuedAsyncBatchRequest:
|
|
241
242
|
"""Runs a file through an uploader.
|
|
242
243
|
|
|
244
|
+
:param file_id: DEPRECATED: use file_ids
|
|
243
245
|
:param depends_on: A list of batch reference keys to process before processing this request
|
|
244
246
|
"""
|
|
245
247
|
args = invoke_uploader_t.Arguments(
|
|
246
248
|
file_id=file_id,
|
|
249
|
+
file_ids=file_ids,
|
|
247
250
|
uploader_key=uploader_key,
|
|
248
251
|
destination=destination,
|
|
249
252
|
)
|
uncountable/types/client_base.py
CHANGED
|
@@ -876,15 +876,18 @@ class ClientMethods(ABC):
|
|
|
876
876
|
def invoke_uploader(
|
|
877
877
|
self,
|
|
878
878
|
*,
|
|
879
|
-
file_id: base_t.ObjectId,
|
|
880
879
|
uploader_key: identifier_t.IdentifierKey,
|
|
881
880
|
destination: generic_upload_t.UploadDestination,
|
|
881
|
+
file_id: typing.Optional[base_t.ObjectId] = None,
|
|
882
|
+
file_ids: typing.Optional[list[base_t.ObjectId]] = None,
|
|
882
883
|
) -> invoke_uploader_t.Data:
|
|
883
884
|
"""Runs a file through an uploader.
|
|
884
885
|
|
|
886
|
+
:param file_id: DEPRECATED: use file_ids
|
|
885
887
|
"""
|
|
886
888
|
args = invoke_uploader_t.Arguments(
|
|
887
889
|
file_id=file_id,
|
|
890
|
+
file_ids=file_ids,
|
|
888
891
|
uploader_key=uploader_key,
|
|
889
892
|
destination=destination,
|
|
890
893
|
)
|
uncountable/types/entity_t.py
CHANGED
|
@@ -111,6 +111,7 @@ __all__: list[str] = [
|
|
|
111
111
|
"recipe_calculation": "Recipe Calculation",
|
|
112
112
|
"recipe_check": "Experiment Check",
|
|
113
113
|
"recipe_export": "Recipe Export",
|
|
114
|
+
"recipe_goal": "Experiment Goal",
|
|
114
115
|
"recipe_ingredient": "Recipe Ingredient",
|
|
115
116
|
"recipe_ingredient_actual": "Recipe Ingredient Actual",
|
|
116
117
|
"recipe_ingredients_compounded": "Recipe Ingredients Compounded",
|
|
@@ -265,6 +266,7 @@ class EntityType(StrEnum):
|
|
|
265
266
|
RECIPE_CALCULATION = "recipe_calculation"
|
|
266
267
|
RECIPE_CHECK = "recipe_check"
|
|
267
268
|
RECIPE_EXPORT = "recipe_export"
|
|
269
|
+
RECIPE_GOAL = "recipe_goal"
|
|
268
270
|
RECIPE_INGREDIENT = "recipe_ingredient"
|
|
269
271
|
RECIPE_INGREDIENT_ACTUAL = "recipe_ingredient_actual"
|
|
270
272
|
RECIPE_INGREDIENTS_COMPOUNDED = "recipe_ingredients_compounded"
|
{UncountablePythonSDK-0.0.73.dist-info → UncountablePythonSDK-0.0.74.dist-info}/top_level.txt
RENAMED
|
File without changes
|