UncountablePythonSDK 0.0.74__py3-none-any.whl → 0.0.75__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.74
3
+ Version: 0.0.75
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
@@ -58,8 +58,8 @@ pkgs/type_spec/emit_io_ts.py,sha256=U03sQBpgRqYOaMKrPCRnYb70YboiCgaZfseCXSzW5NY,
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
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
61
+ pkgs/type_spec/emit_typescript.py,sha256=PL1h2UvTp1PRMkTXH893ZYS3cPUrrupjnLg_9ndZGDQ,8838
62
+ pkgs/type_spec/emit_typescript_util.py,sha256=e2rGSs9OTD-iXwcHfU4V9E35jwMc5qVshhOKMknGrJ8,10319
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
@@ -105,7 +105,7 @@ uncountable/integration/queue_runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
105
105
  uncountable/integration/queue_runner/job_scheduler.py,sha256=n6bM6ZqVOPD0PoJuZV5Y5tuhmw2gI-_p6JbnVlK42uI,5016
106
106
  uncountable/integration/queue_runner/queue_runner.py,sha256=0BmYu5zHdothTevGsB-nXg6MBd1UD-WkP3h1WCKMdQg,710
107
107
  uncountable/integration/queue_runner/types.py,sha256=8qTq29BTSa5rmW6CBlBntP0pNIiDcwu1wHa78pjroS0,219
108
- uncountable/integration/queue_runner/worker.py,sha256=wS_Mv12MtG9ULz2K4nUdivUAxJdZmd6B6GEUhqysG2A,4403
108
+ uncountable/integration/queue_runner/worker.py,sha256=Bwp7_OD4AughY01QQtZxlmZ5yrDmDk1GuijH09xhUkk,4455
109
109
  uncountable/integration/queue_runner/command_server/__init__.py,sha256=gQPVILGpWzCr2i5GJyoqna7AOSFvtn4tav69gB78mTQ,571
110
110
  uncountable/integration/queue_runner/command_server/command_client.py,sha256=DJb0TUVFkiiLBEQzHSN94sTRnuEbutNEgdN39XmnOXI,2046
111
111
  uncountable/integration/queue_runner/command_server/command_server.py,sha256=yyXryhiEC2eGS0yFElLGsVzSKwOuYvj-zp22jQorkv0,2138
@@ -132,7 +132,7 @@ 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=16W0EnH7kyy_sRL_fNn4NBvNhE8NCmmrSad-grKhLus,67489
135
+ uncountable/types/client_base.py,sha256=qTifyQNBOwlspjWccQXg4gOhuwyQDy5z77rlreDynBU,67603
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
@@ -204,8 +204,8 @@ uncountable/types/api/batch/execute_batch_load_async.py,sha256=j5a5dk0_lTJ-YslrB
204
204
  uncountable/types/api/chemical/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
205
205
  uncountable/types/api/chemical/convert_chemical_formats.py,sha256=xLpma1W1O9MzgxM4CCl5GPnpj3dpqRHhKcXr3b_ToAo,1589
206
206
  uncountable/types/api/entity/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
207
- uncountable/types/api/entity/create_entities.py,sha256=3zBPO3_CM9fU2R1EFWQcFcXxCVCNNU2NIsnJLYnojzI,2219
208
- uncountable/types/api/entity/create_entity.py,sha256=elMRdi8VT7CTrPhypQsL9P5gvCLlk5_D_1CUxulnXzA,2331
207
+ uncountable/types/api/entity/create_entities.py,sha256=hG81k_nKD4orTtb5jKIkCarkSbUa3fXAxES6IZVkhL0,2276
208
+ uncountable/types/api/entity/create_entity.py,sha256=BV99ZfkxPfMEGD0YvuMizK25Nll0o0GFho8_Mzb0Clk,2388
209
209
  uncountable/types/api/entity/get_entities_data.py,sha256=gTEZ7Z7T-DWP8BZPNDF4c__EHtf9kAb1sGtHmiGOgnM,1454
210
210
  uncountable/types/api/entity/list_entities.py,sha256=ykbdq4DD31uiRz4i8LH-8LLeA2Lpp_5fWfb5fdyx248,2000
211
211
  uncountable/types/api/entity/lock_entity.py,sha256=mMZx2tWOtuYg0sIftdPsFWgZO5LCav2ubqTw97dCtDU,1197
@@ -277,7 +277,7 @@ uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr
277
277
  uncountable/types/api/triggers/run_trigger.py,sha256=-oZgPyn43xEKSCs81DVNzwaYMCdRJxbM9GY6fsqKwf4,1090
278
278
  uncountable/types/api/uploader/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
279
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,,
280
+ UncountablePythonSDK-0.0.75.dist-info/METADATA,sha256=__fXg5O7uTKPPzAFToY3pOV8EHnNl6uX7UWCNat0E8Y,2051
281
+ UncountablePythonSDK-0.0.75.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
282
+ UncountablePythonSDK-0.0.75.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
283
+ UncountablePythonSDK-0.0.75.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: setuptools (75.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,106 +1,26 @@
1
1
  import io
2
2
  import os
3
- from typing import Any
4
3
 
5
4
  from . import builder, util
6
- from .builder import SpecTypeDefnObject
7
5
  from .config import TypeScriptConfig
8
6
  from .emit_io_ts import emit_type_io_ts
9
7
  from .emit_typescript_util import (
10
- INDENT,
11
8
  MODIFY_NOTICE,
12
9
  EmitTypescriptContext,
10
+ emit_namespace_imports_ts,
11
+ emit_type_ts,
12
+ emit_value_ts,
13
+ resolve_namespace_name,
13
14
  resolve_namespace_ref,
14
- ts_name,
15
15
  ts_type_name,
16
16
  )
17
17
 
18
18
 
19
- def ts_enum_name(name: str, name_case: builder.NameCase) -> str:
20
- if name_case == builder.NameCase.js_upper:
21
- return name.upper()
22
- return ts_name(name, name_case)
23
-
24
-
25
- def _resolve_namespace_name(namespace: builder.SpecNamespace) -> str:
26
- return namespace.name
27
-
28
-
29
- def _emit_value(ctx: EmitTypescriptContext, stype: builder.SpecType, value: Any) -> str:
30
- """Mimics emit_python even if not all types are used in TypeScript yet"""
31
- literal = builder.unwrap_literal_type(stype)
32
- if literal is not None:
33
- return _emit_value(ctx, literal.value_type, literal.value)
34
-
35
- if stype.is_base_type(builder.BaseTypeName.s_string):
36
- assert isinstance(value, str)
37
- return util.encode_common_string(value)
38
- elif stype.is_base_type(builder.BaseTypeName.s_integer):
39
- assert isinstance(value, int)
40
- return str(value)
41
- elif stype.is_base_type(builder.BaseTypeName.s_boolean):
42
- assert isinstance(value, bool)
43
- return "true" if value else "false"
44
- elif stype.is_base_type(builder.BaseTypeName.s_lossy_decimal):
45
- return str(value)
46
- elif stype.is_base_type(builder.BaseTypeName.s_decimal):
47
- return f"'{value}'"
48
- elif isinstance(stype, builder.SpecTypeInstance):
49
- if stype.defn_type.is_base_type(builder.BaseTypeName.s_list):
50
- sub_type = stype.parameters[0]
51
- return "[" + ", ".join([_emit_value(ctx, sub_type, x) for x in value]) + "]"
52
-
53
- if stype.defn_type.is_base_type(builder.BaseTypeName.s_dict):
54
- key_type = stype.parameters[0]
55
- value_type = stype.parameters[1]
56
- return (
57
- "{\n\t"
58
- + ",\n\t".join(
59
- "["
60
- + _emit_value(ctx, key_type, dkey)
61
- + "]: "
62
- + _emit_value(ctx, value_type, dvalue)
63
- for dkey, dvalue in value.items()
64
- )
65
- + "\n}"
66
- )
67
-
68
- if stype.defn_type.is_base_type(builder.BaseTypeName.s_optional):
69
- sub_type = stype.parameters[0]
70
- if value is None:
71
- return "null"
72
- return _emit_value(ctx, sub_type, value)
73
-
74
- elif isinstance(stype, builder.SpecTypeDefnStringEnum):
75
- return f"{refer_to(ctx, stype)}.{ts_enum_name(value, stype.name_case)}"
76
-
77
- raise Exception("invalid constant type", value, stype)
78
-
79
-
80
19
  def emit_typescript(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
81
20
  _emit_types(builder, config)
82
21
  _emit_id_source(builder, config)
83
22
 
84
23
 
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
-
104
24
  def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
105
25
  index_out = io.StringIO()
106
26
  index_out.write(MODIFY_NOTICE)
@@ -109,7 +29,7 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
109
29
 
110
30
  for namespace in sorted(
111
31
  builder.namespaces.values(),
112
- key=lambda ns: _resolve_namespace_name(ns),
32
+ key=lambda ns: resolve_namespace_name(ns),
113
33
  ):
114
34
  ctx = EmitTypescriptContext(out=io.StringIO(), namespace=namespace)
115
35
 
@@ -160,7 +80,7 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
160
80
 
161
81
  if len(namespace.path) == 1:
162
82
  index_out.write(
163
- f"import * as {resolve_namespace_ref(namespace)} from './{_resolve_namespace_name(namespace)}'\n"
83
+ f"import * as {resolve_namespace_ref(namespace)} from './{resolve_namespace_name(namespace)}'\n"
164
84
  ) # noqa: E501
165
85
  index_out_end.write(f"export {{{resolve_namespace_ref(namespace)}}}\n")
166
86
 
@@ -297,164 +217,14 @@ export const apiCall = {wrap_call}(
297
217
  index.write(f"export {{ {api_name} }}\n")
298
218
 
299
219
 
300
- def emit_type_ts(ctx: EmitTypescriptContext, stype: builder.SpecType) -> None:
301
- if not isinstance(stype, builder.SpecTypeDefn):
302
- return
303
-
304
- if stype.is_base or stype.is_predefined:
305
- return
306
-
307
- ctx.out.write("\n")
308
- ctx.out.write(MODIFY_NOTICE)
309
-
310
- if isinstance(stype, builder.SpecTypeDefnExternal):
311
- assert not stype.is_exported, "expecting private names"
312
- ctx.out.write(stype.external_map["ts"])
313
- ctx.out.write("\n")
314
- return
315
-
316
- assert stype.is_exported, "expecting exported names"
317
- if isinstance(stype, builder.SpecTypeDefnAlias):
318
- ctx.out.write(f"export type {stype.name} = {refer_to(ctx, stype.alias)}\n")
319
- return
320
-
321
- if isinstance(stype, builder.SpecTypeDefnUnion):
322
- ctx.out.write(
323
- f"export type {stype.name} = {refer_to(ctx, stype.get_backing_type())}\n"
324
- )
325
- return
326
-
327
- if isinstance(stype, builder.SpecTypeDefnStringEnum):
328
- ctx.out.write(f"export enum {stype.name} {{\n")
329
- assert stype.values
330
- for name, entry in stype.values.items():
331
- ctx.out.write(
332
- f'{INDENT}{ts_enum_name(name, stype.name_case)} = "{entry.value}",\n'
333
- )
334
- ctx.out.write("}\n")
335
- return
336
-
337
- assert isinstance(stype, builder.SpecTypeDefnObject)
338
- assert stype.base is not None
339
-
340
- base_type = ""
341
- if not stype.base.is_base:
342
- base_type = f"{refer_to(ctx, stype.base)} & "
343
-
344
- if stype.properties is None and base_type == "":
345
- ctx.out.write(f"export type {stype.name} = TEmpty\n")
346
- elif stype.properties is None:
347
- ctx.out.write(f"export type {stype.name} = {base_type}{{}}\n")
348
- else:
349
- if isinstance(stype, SpecTypeDefnObject) and len(stype.parameters) > 0:
350
- full_type_name = f'{stype.name}<{", ".join(stype.parameters)}>'
351
- else:
352
- full_type_name = stype.name
353
- ctx.out.write(f"export type {full_type_name} = {base_type}{{")
354
- ctx.out.write("\n")
355
- for prop in stype.properties.values():
356
- ref_type = refer_to(ctx, prop.spec_type)
357
- prop_name = ts_name(prop.name, prop.name_case)
358
- if prop.has_default and not prop.parse_require:
359
- # For now, we'll assume the generated types with defaults are meant as
360
- # arguments, thus treat like extant==missing
361
- # IMPROVE: if we can decide they are meant as output instead, then
362
- # they should be marked as required
363
- ctx.out.write(f"{INDENT}{prop_name}?: {ref_type}")
364
- elif prop.extant == builder.PropertyExtant.missing:
365
- # Unlike optional below, missing does not imply null is possible. They
366
- # treated distinctly.
367
- ctx.out.write(f"{INDENT}{prop_name}?: {ref_type}")
368
- elif prop.extant == builder.PropertyExtant.optional:
369
- # Need to add in |null since Python side can produce null's right now
370
- # IMPROVE: It would be better if the serializer could instead omit the None's
371
- # Dropping the null should be forward compatible
372
- ctx.out.write(f"{INDENT}{prop_name}?: {ref_type} | null")
373
- else:
374
- ctx.out.write(f"{INDENT}{prop_name}: {ref_type}")
375
- ctx.out.write("\n")
376
- ctx.out.write("}\n")
377
-
378
-
379
220
  def _emit_constant(ctx: EmitTypescriptContext, sconst: builder.SpecConstant) -> None:
380
221
  ctx.out.write("\n\n")
381
222
  ctx.out.write(MODIFY_NOTICE)
382
- value = _emit_value(ctx, sconst.value_type, sconst.value)
223
+ value = emit_value_ts(ctx, sconst.value_type, sconst.value)
383
224
  const_name = sconst.name.upper()
384
225
  ctx.out.write(f"export const {const_name} = {value}\n")
385
226
 
386
227
 
387
- base_name_map = {
388
- builder.BaseTypeName.s_boolean: "boolean",
389
- builder.BaseTypeName.s_date: "string", # IMPROVE: Aliased DateStr
390
- builder.BaseTypeName.s_date_time: "string", # IMPROVE: Aliased DateTimeStr
391
- # Decimal's are marked as to_string_values thus are strings in the front-end
392
- builder.BaseTypeName.s_decimal: "string",
393
- builder.BaseTypeName.s_dict: "PartialRecord",
394
- builder.BaseTypeName.s_integer: "number",
395
- builder.BaseTypeName.s_lossy_decimal: "number",
396
- builder.BaseTypeName.s_opaque_key: "string",
397
- builder.BaseTypeName.s_none: "null",
398
- builder.BaseTypeName.s_string: "string",
399
- # UNC: global types
400
- builder.BaseTypeName.s_json_value: "JsonValue",
401
- }
402
-
403
-
404
- def refer_to(ctx: EmitTypescriptContext, stype: builder.SpecType) -> str:
405
- return refer_to_impl(ctx, stype)[0]
406
-
407
-
408
- def refer_to_impl(
409
- ctx: EmitTypescriptContext, stype: builder.SpecType
410
- ) -> tuple[str, bool]:
411
- """
412
- @return (string-specific, multiple-types)
413
- """
414
- if isinstance(stype, builder.SpecTypeInstance):
415
- if stype.defn_type.name == builder.BaseTypeName.s_list:
416
- spec, multi = refer_to_impl(ctx, stype.parameters[0])
417
- return f"({spec})[]" if multi else f"{spec}[]", False
418
- if stype.defn_type.name == builder.BaseTypeName.s_readonly_array:
419
- spec, multi = refer_to_impl(ctx, stype.parameters[0])
420
- return f"readonly ({spec})[]" if multi else f"readonly {spec}[]", False
421
- if stype.defn_type.name == builder.BaseTypeName.s_union:
422
- return (
423
- f'({" | ".join([refer_to(ctx, p) for p in stype.parameters])})',
424
- False,
425
- )
426
- if stype.defn_type.name == builder.BaseTypeName.s_literal:
427
- parts = []
428
- for parameter in stype.parameters:
429
- assert isinstance(parameter, builder.SpecTypeLiteralWrapper)
430
- parts.append(refer_to(ctx, parameter))
431
- return f'({" | ".join(parts)})', False
432
- if stype.defn_type.name == builder.BaseTypeName.s_optional:
433
- return f"{refer_to(ctx, stype.parameters[0])} | null", True
434
- if stype.defn_type.name == builder.BaseTypeName.s_tuple:
435
- return f"[{", ".join([refer_to(ctx, p) for p in stype.parameters])}]", False
436
- params = ", ".join([refer_to(ctx, p) for p in stype.parameters])
437
- return f"{refer_to(ctx, stype.defn_type)}<{params}>", False
438
-
439
- if isinstance(stype, builder.SpecTypeLiteralWrapper):
440
- return _emit_value(ctx, stype.value_type, stype.value), False
441
-
442
- if isinstance(stype, builder.SpecTypeGenericParameter):
443
- return stype.name, False
444
-
445
- assert isinstance(stype, builder.SpecTypeDefn)
446
- if stype.is_base: # assume correct namespace
447
- if stype.name == builder.BaseTypeName.s_list:
448
- return "any[]", False # TODO: generic type
449
- return base_name_map[builder.BaseTypeName(stype.name)], False
450
-
451
- if stype.namespace == ctx.namespace:
452
- return stype.name, False
453
-
454
- ctx.namespaces.add(stype.namespace)
455
- return f"{resolve_namespace_ref(stype.namespace)}.{stype.name}", False
456
-
457
-
458
228
  def _emit_id_source(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
459
229
  id_source_output = config.id_source_output
460
230
  if id_source_output is None:
@@ -1,4 +1,5 @@
1
1
  import io
2
+ import typing
2
3
  from dataclasses import dataclass, field
3
4
 
4
5
  from . import builder, util
@@ -8,6 +9,23 @@ INDENT = " "
8
9
  MODIFY_NOTICE = "// DO NOT MODIFY -- This file is generated by type_spec\n"
9
10
 
10
11
 
12
+ base_name_map = {
13
+ builder.BaseTypeName.s_boolean: "boolean",
14
+ builder.BaseTypeName.s_date: "string", # IMPROVE: Aliased DateStr
15
+ builder.BaseTypeName.s_date_time: "string", # IMPROVE: Aliased DateTimeStr
16
+ # Decimal's are marked as to_string_values thus are strings in the front-end
17
+ builder.BaseTypeName.s_decimal: "string",
18
+ builder.BaseTypeName.s_dict: "PartialRecord",
19
+ builder.BaseTypeName.s_integer: "number",
20
+ builder.BaseTypeName.s_lossy_decimal: "number",
21
+ builder.BaseTypeName.s_opaque_key: "string",
22
+ builder.BaseTypeName.s_none: "null",
23
+ builder.BaseTypeName.s_string: "string",
24
+ # UNC: global types
25
+ builder.BaseTypeName.s_json_value: "JsonValue",
26
+ }
27
+
28
+
11
29
  @dataclass(kw_only=True)
12
30
  class EmitTypescriptContext:
13
31
  out: io.StringIO
@@ -28,3 +46,220 @@ def ts_name(name: str, name_case: builder.NameCase) -> str:
28
46
  return name
29
47
  bits = util.split_any_name(name)
30
48
  return "".join([bits[0], *[x.title() for x in bits[1:]]])
49
+
50
+
51
+ def emit_value_ts(
52
+ ctx: EmitTypescriptContext, stype: builder.SpecType, value: typing.Any
53
+ ) -> str:
54
+ """Mimics emit_python even if not all types are used in TypeScript yet"""
55
+ literal = builder.unwrap_literal_type(stype)
56
+ if literal is not None:
57
+ return emit_value_ts(ctx, literal.value_type, literal.value)
58
+
59
+ if stype.is_base_type(builder.BaseTypeName.s_string):
60
+ assert isinstance(value, str)
61
+ return util.encode_common_string(value)
62
+ elif stype.is_base_type(builder.BaseTypeName.s_integer):
63
+ assert isinstance(value, int)
64
+ return str(value)
65
+ elif stype.is_base_type(builder.BaseTypeName.s_boolean):
66
+ assert isinstance(value, bool)
67
+ return "true" if value else "false"
68
+ elif stype.is_base_type(builder.BaseTypeName.s_lossy_decimal):
69
+ return str(value)
70
+ elif stype.is_base_type(builder.BaseTypeName.s_decimal):
71
+ return f"'{value}'"
72
+ elif isinstance(stype, builder.SpecTypeInstance):
73
+ if stype.defn_type.is_base_type(builder.BaseTypeName.s_list):
74
+ sub_type = stype.parameters[0]
75
+ return (
76
+ "[" + ", ".join([emit_value_ts(ctx, sub_type, x) for x in value]) + "]"
77
+ )
78
+
79
+ if stype.defn_type.is_base_type(builder.BaseTypeName.s_dict):
80
+ key_type = stype.parameters[0]
81
+ value_type = stype.parameters[1]
82
+ return (
83
+ "{\n\t"
84
+ + ",\n\t".join(
85
+ "["
86
+ + emit_value_ts(ctx, key_type, dkey)
87
+ + "]: "
88
+ + emit_value_ts(ctx, value_type, dvalue)
89
+ for dkey, dvalue in value.items()
90
+ )
91
+ + "\n}"
92
+ )
93
+
94
+ if stype.defn_type.is_base_type(builder.BaseTypeName.s_optional):
95
+ sub_type = stype.parameters[0]
96
+ if value is None:
97
+ return "null"
98
+ return emit_value_ts(ctx, sub_type, value)
99
+
100
+ elif isinstance(stype, builder.SpecTypeDefnStringEnum):
101
+ return f"{refer_to(ctx, stype)}.{ts_enum_name(value, stype.name_case)}"
102
+
103
+ raise Exception("invalid constant type", value, stype)
104
+
105
+
106
+ def emit_type_ts(ctx: EmitTypescriptContext, stype: builder.SpecType) -> None:
107
+ if not isinstance(stype, builder.SpecTypeDefn):
108
+ return
109
+
110
+ if stype.is_base or stype.is_predefined:
111
+ return
112
+
113
+ ctx.out.write("\n")
114
+ ctx.out.write(MODIFY_NOTICE)
115
+
116
+ if isinstance(stype, builder.SpecTypeDefnExternal):
117
+ assert not stype.is_exported, "expecting private names"
118
+ ctx.out.write(stype.external_map["ts"])
119
+ ctx.out.write("\n")
120
+ return
121
+
122
+ assert stype.is_exported, "expecting exported names"
123
+ if isinstance(stype, builder.SpecTypeDefnAlias):
124
+ ctx.out.write(f"export type {stype.name} = {refer_to(ctx, stype.alias)}\n")
125
+ return
126
+
127
+ if isinstance(stype, builder.SpecTypeDefnUnion):
128
+ ctx.out.write(
129
+ f"export type {stype.name} = {refer_to(ctx, stype.get_backing_type())}\n"
130
+ )
131
+ return
132
+
133
+ if isinstance(stype, builder.SpecTypeDefnStringEnum):
134
+ ctx.out.write(f"export enum {stype.name} {{\n")
135
+ assert stype.values
136
+ for name, entry in stype.values.items():
137
+ ctx.out.write(
138
+ f'{INDENT}{ts_enum_name(name, stype.name_case)} = "{entry.value}",\n'
139
+ )
140
+ ctx.out.write("}\n")
141
+ return
142
+
143
+ assert isinstance(stype, builder.SpecTypeDefnObject)
144
+ assert stype.base is not None
145
+
146
+ base_type = ""
147
+ if not stype.base.is_base:
148
+ base_type = f"{refer_to(ctx, stype.base)} & "
149
+
150
+ if stype.properties is None and base_type == "":
151
+ ctx.out.write(f"export type {stype.name} = TEmpty\n")
152
+ elif stype.properties is None:
153
+ ctx.out.write(f"export type {stype.name} = {base_type}{{}}\n")
154
+ else:
155
+ if isinstance(stype, builder.SpecTypeDefnObject) and len(stype.parameters) > 0:
156
+ full_type_name = f'{stype.name}<{", ".join(stype.parameters)}>'
157
+ else:
158
+ full_type_name = stype.name
159
+ ctx.out.write(f"export type {full_type_name} = {base_type}{{")
160
+ ctx.out.write("\n")
161
+ for prop in stype.properties.values():
162
+ ref_type = refer_to(ctx, prop.spec_type)
163
+ prop_name = ts_name(prop.name, prop.name_case)
164
+ if prop.has_default and not prop.parse_require:
165
+ # For now, we'll assume the generated types with defaults are meant as
166
+ # arguments, thus treat like extant==missing
167
+ # IMPROVE: if we can decide they are meant as output instead, then
168
+ # they should be marked as required
169
+ ctx.out.write(f"{INDENT}{prop_name}?: {ref_type}")
170
+ elif prop.extant == builder.PropertyExtant.missing:
171
+ # Unlike optional below, missing does not imply null is possible. They
172
+ # treated distinctly.
173
+ ctx.out.write(f"{INDENT}{prop_name}?: {ref_type}")
174
+ elif prop.extant == builder.PropertyExtant.optional:
175
+ # Need to add in |null since Python side can produce null's right now
176
+ # IMPROVE: It would be better if the serializer could instead omit the None's
177
+ # Dropping the null should be forward compatible
178
+ ctx.out.write(f"{INDENT}{prop_name}?: {ref_type} | null")
179
+ else:
180
+ ctx.out.write(f"{INDENT}{prop_name}: {ref_type}")
181
+ ctx.out.write("\n")
182
+ ctx.out.write("}\n")
183
+
184
+
185
+ def refer_to(ctx: EmitTypescriptContext, stype: builder.SpecType) -> str:
186
+ return refer_to_impl(ctx, stype)[0]
187
+
188
+
189
+ def refer_to_impl(
190
+ ctx: EmitTypescriptContext, stype: builder.SpecType
191
+ ) -> tuple[str, bool]:
192
+ """
193
+ @return (string-specific, multiple-types)
194
+ """
195
+ if isinstance(stype, builder.SpecTypeInstance):
196
+ if stype.defn_type.name == builder.BaseTypeName.s_list:
197
+ spec, multi = refer_to_impl(ctx, stype.parameters[0])
198
+ return f"({spec})[]" if multi else f"{spec}[]", False
199
+ if stype.defn_type.name == builder.BaseTypeName.s_readonly_array:
200
+ spec, multi = refer_to_impl(ctx, stype.parameters[0])
201
+ return f"readonly ({spec})[]" if multi else f"readonly {spec}[]", False
202
+ if stype.defn_type.name == builder.BaseTypeName.s_union:
203
+ return (
204
+ f'({" | ".join([refer_to(ctx, p) for p in stype.parameters])})',
205
+ False,
206
+ )
207
+ if stype.defn_type.name == builder.BaseTypeName.s_literal:
208
+ parts = []
209
+ for parameter in stype.parameters:
210
+ assert isinstance(parameter, builder.SpecTypeLiteralWrapper)
211
+ parts.append(refer_to(ctx, parameter))
212
+ return f'({" | ".join(parts)})', False
213
+ if stype.defn_type.name == builder.BaseTypeName.s_optional:
214
+ return f"{refer_to(ctx, stype.parameters[0])} | null", True
215
+ if stype.defn_type.name == builder.BaseTypeName.s_tuple:
216
+ return f"[{", ".join([refer_to(ctx, p) for p in stype.parameters])}]", False
217
+ params = ", ".join([refer_to(ctx, p) for p in stype.parameters])
218
+ return f"{refer_to(ctx, stype.defn_type)}<{params}>", False
219
+
220
+ if isinstance(stype, builder.SpecTypeLiteralWrapper):
221
+ return emit_value_ts(ctx, stype.value_type, stype.value), False
222
+
223
+ if isinstance(stype, builder.SpecTypeGenericParameter):
224
+ return stype.name, False
225
+
226
+ assert isinstance(stype, builder.SpecTypeDefn)
227
+ if stype.is_base: # assume correct namespace
228
+ if stype.name == builder.BaseTypeName.s_list:
229
+ return "any[]", False # TODO: generic type
230
+ return base_name_map[builder.BaseTypeName(stype.name)], False
231
+
232
+ if stype.namespace == ctx.namespace:
233
+ return stype.name, False
234
+
235
+ ctx.namespaces.add(stype.namespace)
236
+ return f"{resolve_namespace_ref(stype.namespace)}.{stype.name}", False
237
+
238
+
239
+ def ts_enum_name(name: str, name_case: builder.NameCase) -> str:
240
+ if name_case == builder.NameCase.js_upper:
241
+ return name.upper()
242
+ return ts_name(name, name_case)
243
+
244
+
245
+ def resolve_namespace_name(namespace: builder.SpecNamespace) -> str:
246
+ return namespace.name
247
+
248
+
249
+ def emit_namespace_imports_ts(
250
+ namespaces: set[builder.SpecNamespace],
251
+ out: io.StringIO,
252
+ current_namespace: builder.SpecNamespace,
253
+ ) -> None:
254
+ for ns in sorted(
255
+ namespaces,
256
+ key=lambda name: resolve_namespace_name(name),
257
+ ):
258
+ import_as = resolve_namespace_ref(ns)
259
+ import_path = (
260
+ "./"
261
+ if len(current_namespace.path) == 1
262
+ else "../" * (len(current_namespace.path) - 1)
263
+ )
264
+ import_from = f"{import_path}{resolve_namespace_name(ns)}"
265
+ out.write(f'import * as {import_as} from "{import_from}"\n') # noqa: E501
@@ -86,23 +86,23 @@ def run_queued_job(
86
86
  profile_metadata=job_details.profile_metadata,
87
87
  job_definition=job_details.job_definition,
88
88
  )
89
- client = construct_uncountable_client(
90
- profile_meta=job_details.profile_metadata, job_logger=job_logger
91
- )
92
- batch_processor = AsyncBatchProcessor(client=client)
89
+ try:
90
+ client = construct_uncountable_client(
91
+ profile_meta=job_details.profile_metadata, job_logger=job_logger
92
+ )
93
+ batch_processor = AsyncBatchProcessor(client=client)
93
94
 
94
- payload = _resolve_queued_job_payload(queued_job)
95
+ payload = _resolve_queued_job_payload(queued_job)
95
96
 
96
- args = JobArguments(
97
- job_definition=job_details.job_definition,
98
- client=client,
99
- batch_processor=batch_processor,
100
- profile_metadata=job_details.profile_metadata,
101
- logger=job_logger,
102
- payload=payload,
103
- )
97
+ args = JobArguments(
98
+ job_definition=job_details.job_definition,
99
+ client=client,
100
+ batch_processor=batch_processor,
101
+ profile_metadata=job_details.profile_metadata,
102
+ logger=job_logger,
103
+ payload=payload,
104
+ )
104
105
 
105
- try:
106
106
  return execute_job(
107
107
  args=args,
108
108
  profile_metadata=job_details.profile_metadata,
@@ -41,7 +41,7 @@ class EntityToCreate:
41
41
  @dataclasses.dataclass(kw_only=True)
42
42
  class Arguments:
43
43
  definition_id: base_t.ObjectId
44
- entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.INVENTORY_AMOUNT], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS], typing.Literal[entity_t.EntityType.FIELD_OPTION_SET], typing.Literal[entity_t.EntityType.WEBHOOK], typing.Literal[entity_t.EntityType.SPECS], typing.Literal[entity_t.EntityType.GOAL], typing.Literal[entity_t.EntityType.INGREDIENT_TAG_MAP], typing.Literal[entity_t.EntityType.INGREDIENT_TAG], typing.Literal[entity_t.EntityType.OUTPUT]]
44
+ entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.INVENTORY_AMOUNT], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS], typing.Literal[entity_t.EntityType.FIELD_OPTION_SET], typing.Literal[entity_t.EntityType.WEBHOOK], typing.Literal[entity_t.EntityType.SPECS], typing.Literal[entity_t.EntityType.GOAL], typing.Literal[entity_t.EntityType.INGREDIENT_TAG_MAP], typing.Literal[entity_t.EntityType.INGREDIENT_TAG], typing.Literal[entity_t.EntityType.CONDITION_PARAMETER], typing.Literal[entity_t.EntityType.OUTPUT]]
45
45
  entities_to_create: list[EntityToCreate]
46
46
 
47
47
 
@@ -44,7 +44,7 @@ class EntityFieldInitialValue:
44
44
  @dataclasses.dataclass(kw_only=True)
45
45
  class Arguments:
46
46
  definition_id: base_t.ObjectId
47
- entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.INVENTORY_AMOUNT], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS], typing.Literal[entity_t.EntityType.FIELD_OPTION_SET], typing.Literal[entity_t.EntityType.WEBHOOK], typing.Literal[entity_t.EntityType.SPECS], typing.Literal[entity_t.EntityType.GOAL], typing.Literal[entity_t.EntityType.INGREDIENT_TAG_MAP], typing.Literal[entity_t.EntityType.INGREDIENT_TAG], typing.Literal[entity_t.EntityType.OUTPUT]]
47
+ entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.INVENTORY_AMOUNT], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS], typing.Literal[entity_t.EntityType.FIELD_OPTION_SET], typing.Literal[entity_t.EntityType.WEBHOOK], typing.Literal[entity_t.EntityType.SPECS], typing.Literal[entity_t.EntityType.GOAL], typing.Literal[entity_t.EntityType.INGREDIENT_TAG_MAP], typing.Literal[entity_t.EntityType.INGREDIENT_TAG], typing.Literal[entity_t.EntityType.CONDITION_PARAMETER], typing.Literal[entity_t.EntityType.OUTPUT]]
48
48
  field_values: typing.Optional[typing.Optional[list[field_values_t.FieldRefNameValue]]] = None
49
49
 
50
50
 
@@ -257,7 +257,7 @@ class ClientMethods(ABC):
257
257
  self,
258
258
  *,
259
259
  definition_id: base_t.ObjectId,
260
- entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.INVENTORY_AMOUNT], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS], typing.Literal[entity_t.EntityType.FIELD_OPTION_SET], typing.Literal[entity_t.EntityType.WEBHOOK], typing.Literal[entity_t.EntityType.SPECS], typing.Literal[entity_t.EntityType.GOAL], typing.Literal[entity_t.EntityType.INGREDIENT_TAG_MAP], typing.Literal[entity_t.EntityType.INGREDIENT_TAG], typing.Literal[entity_t.EntityType.OUTPUT]],
260
+ entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.INVENTORY_AMOUNT], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS], typing.Literal[entity_t.EntityType.FIELD_OPTION_SET], typing.Literal[entity_t.EntityType.WEBHOOK], typing.Literal[entity_t.EntityType.SPECS], typing.Literal[entity_t.EntityType.GOAL], typing.Literal[entity_t.EntityType.INGREDIENT_TAG_MAP], typing.Literal[entity_t.EntityType.INGREDIENT_TAG], typing.Literal[entity_t.EntityType.CONDITION_PARAMETER], typing.Literal[entity_t.EntityType.OUTPUT]],
261
261
  entities_to_create: list[create_entities_t.EntityToCreate],
262
262
  ) -> create_entities_t.Data:
263
263
  """Creates new Uncountable entities
@@ -282,7 +282,7 @@ class ClientMethods(ABC):
282
282
  self,
283
283
  *,
284
284
  definition_id: base_t.ObjectId,
285
- entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.INVENTORY_AMOUNT], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS], typing.Literal[entity_t.EntityType.FIELD_OPTION_SET], typing.Literal[entity_t.EntityType.WEBHOOK], typing.Literal[entity_t.EntityType.SPECS], typing.Literal[entity_t.EntityType.GOAL], typing.Literal[entity_t.EntityType.INGREDIENT_TAG_MAP], typing.Literal[entity_t.EntityType.INGREDIENT_TAG], typing.Literal[entity_t.EntityType.OUTPUT]],
285
+ entity_type: typing.Union[typing.Literal[entity_t.EntityType.LAB_REQUEST], typing.Literal[entity_t.EntityType.APPROVAL], typing.Literal[entity_t.EntityType.CUSTOM_ENTITY], typing.Literal[entity_t.EntityType.INVENTORY_AMOUNT], typing.Literal[entity_t.EntityType.TASK], typing.Literal[entity_t.EntityType.PROJECT], typing.Literal[entity_t.EntityType.EQUIPMENT], typing.Literal[entity_t.EntityType.INV_LOCAL_LOCATIONS], typing.Literal[entity_t.EntityType.FIELD_OPTION_SET], typing.Literal[entity_t.EntityType.WEBHOOK], typing.Literal[entity_t.EntityType.SPECS], typing.Literal[entity_t.EntityType.GOAL], typing.Literal[entity_t.EntityType.INGREDIENT_TAG_MAP], typing.Literal[entity_t.EntityType.INGREDIENT_TAG], typing.Literal[entity_t.EntityType.CONDITION_PARAMETER], typing.Literal[entity_t.EntityType.OUTPUT]],
286
286
  field_values: typing.Optional[typing.Optional[list[field_values_t.FieldRefNameValue]]] = None,
287
287
  ) -> create_entity_t.Data:
288
288
  """Creates a new Uncountable entity