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

@@ -19,17 +19,17 @@ class HttpExample(CustomHttpJob):
19
19
  @staticmethod
20
20
  def validate_request(
21
21
  *,
22
- request: GenericHttpRequest,
23
- job_definition: job_definition_t.HttpJobDefinitionBase,
24
- profile_meta: job_definition_t.ProfileMetadata,
22
+ request: GenericHttpRequest, # noqa: ARG004
23
+ job_definition: job_definition_t.HttpJobDefinitionBase, # noqa: ARG004
24
+ profile_meta: job_definition_t.ProfileMetadata, # noqa: ARG004
25
25
  ) -> None:
26
26
  return None
27
27
 
28
28
  @staticmethod
29
29
  def handle_request(
30
30
  *,
31
- request: GenericHttpRequest,
32
- job_definition: job_definition_t.HttpJobDefinitionBase,
33
- profile_meta: job_definition_t.ProfileMetadata,
31
+ request: GenericHttpRequest, # noqa: ARG004
32
+ job_definition: job_definition_t.HttpJobDefinitionBase, # noqa: ARG004
33
+ profile_meta: job_definition_t.ProfileMetadata, # noqa: ARG004
34
34
  ) -> GenericHttpResponse:
35
35
  return GenericHttpResponse(response="OK", status_code=200)
@@ -0,0 +1,38 @@
1
+ from dataclasses import dataclass
2
+
3
+ from uncountable.integration.job import JobArguments, WebhookJob, register_job
4
+ from uncountable.types import base_t, entity_t, job_definition_t
5
+
6
+
7
+ @dataclass(kw_only=True)
8
+ class InstrumentPayload:
9
+ equipment_id: base_t.ObjectId
10
+
11
+
12
+ @register_job
13
+ class InstrumentExample(WebhookJob[InstrumentPayload]):
14
+ def run(
15
+ self, args: JobArguments, payload: InstrumentPayload
16
+ ) -> job_definition_t.JobResult:
17
+ equipment_data = args.client.get_entities_data(
18
+ entity_type=entity_t.EntityType.EQUIPMENT,
19
+ entity_ids=[payload.equipment_id],
20
+ ).entity_details[0]
21
+
22
+ # Load the instrument's connection details from the entity
23
+ instrument_id = None
24
+ for field in equipment_data.field_values:
25
+ if field.field_ref_name == "ins_instrument_id":
26
+ instrument_id = field.value
27
+
28
+ if instrument_id is None:
29
+ args.logger.log_error("Could not find instrument ID")
30
+ return job_definition_t.JobResult(success=False)
31
+
32
+ args.logger.log_info(f"Instrument ID: {instrument_id}")
33
+
34
+ return job_definition_t.JobResult(success=True)
35
+
36
+ @property
37
+ def webhook_payload_type(self) -> type:
38
+ return InstrumentPayload
@@ -75,3 +75,12 @@ jobs:
75
75
  executor:
76
76
  type: script
77
77
  import_path: example_runsheet_wh
78
+ - id: example_instrument
79
+ type: webhook
80
+ name: Webhook Instrument Connection
81
+ signature_key_secret:
82
+ type: env
83
+ env_key: WH_INSTRUMENT_SIGNATURE_KEY
84
+ executor:
85
+ type: script
86
+ import_path: example_instrument
pkgs/type_spec/builder.py CHANGED
@@ -15,12 +15,23 @@ from typing import Any, Self
15
15
  from . import util
16
16
  from .cross_output_links import CrossOutputPaths
17
17
  from .non_discriminated_union_exceptions import NON_DISCRIMINATED_UNION_EXCEPTIONS
18
- from .util import parse_type_str, unused
18
+ from .util import parse_type_str
19
19
 
20
20
  RawDict = dict[Any, Any]
21
21
  EndpointKey = str
22
22
 
23
23
 
24
+ class PathMapping(StrEnum):
25
+ NO_MAPPING = "no_mapping"
26
+ DEFAULT_MAPPING = "default_mapping"
27
+
28
+
29
+ @dataclass(kw_only=True)
30
+ class APIEndpointInfo:
31
+ root_path: str
32
+ path_mapping: PathMapping
33
+
34
+
24
35
  class StabilityLevel(StrEnum):
25
36
  """These are currently used for open api,
26
37
  see: https://github.com/Tufin/oasdiff/blob/main/docs/STABILITY.md
@@ -835,7 +846,7 @@ class _EndpointPathDetails:
835
846
 
836
847
 
837
848
  def _resolve_endpoint_path(
838
- path: str, api_endpoints: dict[EndpointKey, str]
849
+ path: str, api_endpoints: dict[EndpointKey, APIEndpointInfo]
839
850
  ) -> _EndpointPathDetails:
840
851
  root_path_source = path.split("/")[0]
841
852
  root_match = RE_ENDPOINT_ROOT.fullmatch(root_path_source)
@@ -843,7 +854,7 @@ def _resolve_endpoint_path(
843
854
  raise Exception(f"invalid-api-path-root:{root_path_source}")
844
855
 
845
856
  root_var = root_match.group(1)
846
- root_path = api_endpoints[root_var]
857
+ root_path = api_endpoints[root_var].root_path
847
858
 
848
859
  _, *rest_path = path.split("/", 1)
849
860
  resolved_path = "/".join([root_path] + rest_path)
@@ -911,6 +922,7 @@ class SpecEndpoint:
911
922
  stability_level: StabilityLevel | None
912
923
  # Don't emit TypeScript endpoint code
913
924
  suppress_ts: bool
925
+ deprecated: bool = False
914
926
  async_batch_path: str | None = None
915
927
  result_type: ResultType = ResultType.json
916
928
  has_attachment: bool = False
@@ -928,13 +940,13 @@ class SpecEndpoint:
928
940
  pass
929
941
 
930
942
  def process(self, builder: SpecBuilder, data: RawDict) -> None:
931
- unused(builder)
932
943
  util.check_fields(
933
944
  data,
934
945
  [
935
946
  "method",
936
947
  "path",
937
948
  "data_loader",
949
+ "deprecated",
938
950
  "is_sdk",
939
951
  "stability_level",
940
952
  "async_batch_path",
@@ -954,6 +966,7 @@ class SpecEndpoint:
954
966
  data_loader = data.get("data_loader", False)
955
967
  assert isinstance(data_loader, bool)
956
968
  self.data_loader = data_loader
969
+ self.deprecated = data.get("deprecated", False)
957
970
 
958
971
  is_sdk = data.get("is_sdk", EndpointEmitType.EMIT_NOTHING)
959
972
 
@@ -1346,7 +1359,7 @@ class SpecBuilder:
1346
1359
  def __init__(
1347
1360
  self,
1348
1361
  *,
1349
- api_endpoints: dict[EndpointKey, str],
1362
+ api_endpoints: dict[EndpointKey, APIEndpointInfo],
1350
1363
  top_namespace: str,
1351
1364
  cross_output_paths: CrossOutputPaths | None,
1352
1365
  ) -> None:
pkgs/type_spec/config.py CHANGED
@@ -4,6 +4,7 @@ from dataclasses import dataclass
4
4
  from typing import Self, TypeVar
5
5
 
6
6
  from pkgs.serialization import yaml
7
+ from pkgs.type_spec.builder import APIEndpointInfo, EndpointKey
7
8
 
8
9
  ConfigValueType = str | None | Mapping[str, str | None] | list[str]
9
10
 
@@ -19,6 +20,22 @@ def _parse_string_lookup(
19
20
  }
20
21
 
21
22
 
23
+ VT = TypeVar("VT")
24
+
25
+
26
+ def _parse_data_lookup(
27
+ key: str,
28
+ raw_value: ConfigValueType,
29
+ conv_func: type[VT],
30
+ ) -> dict[str, VT]:
31
+ assert isinstance(raw_value, dict), f"{key} must be key/values"
32
+ return {
33
+ k: conv_func(**v)
34
+ for k, v in raw_value.items()
35
+ if v is not None and isinstance(v, dict)
36
+ }
37
+
38
+
22
39
  @dataclass(kw_only=True)
23
40
  class BaseLanguageConfig:
24
41
  types_output: (
@@ -31,7 +48,9 @@ class BaseLanguageConfig:
31
48
 
32
49
  @dataclass(kw_only=True)
33
50
  class TypeScriptConfig(BaseLanguageConfig):
34
- routes_output: str # folder for generate route files will be located.
51
+ endpoint_to_routes_output: dict[
52
+ EndpointKey, str
53
+ ] # folder for generate route files will be located.
35
54
  type_info_output: str # folder for generated type info files
36
55
  id_source_output: str | None = None # folder for emitted id source maps.
37
56
  endpoint_to_frontend_app_type: dict[
@@ -39,7 +58,7 @@ class TypeScriptConfig(BaseLanguageConfig):
39
58
  ] # map from api_endpoint to frontend app type
40
59
 
41
60
  def __post_init__(self: Self) -> None:
42
- self.routes_output = self.routes_output
61
+ self.endpoint_to_routes_output = self.endpoint_to_routes_output
43
62
  self.type_info_output = os.path.abspath(self.type_info_output)
44
63
  self.id_source_output = (
45
64
  os.path.abspath(self.id_source_output)
@@ -100,7 +119,7 @@ class OpenAPIConfig(BaseLanguageConfig):
100
119
  class Config:
101
120
  top_namespace: str
102
121
  type_spec_types: list[str] # folders containing the yaml type spec definitions
103
- api_endpoint: dict[str, str]
122
+ api_endpoint: dict[str, APIEndpointInfo]
104
123
  # languages
105
124
  typescript: TypeScriptConfig | None
106
125
  python: PythonConfig
@@ -125,8 +144,10 @@ def parse_yaml_config(config_file: str) -> Config:
125
144
  )
126
145
  type_spec_types = [os.path.abspath(folder) for folder in raw_type_spec_types]
127
146
 
128
- api_endpoint = _parse_string_lookup(
129
- "api_endpoint", raw_config.get("api_endpoint", {}), lambda x: x
147
+ api_endpoint = _parse_data_lookup(
148
+ "api_endpoint",
149
+ raw_config.get("api_endpoint", {}),
150
+ APIEndpointInfo,
130
151
  )
131
152
 
132
153
  raw_typescript = raw_config.get("typescript")
@@ -21,7 +21,7 @@ def get_python_stub_file_path(
21
21
  class CrossOutputPaths:
22
22
  python_types_output: str
23
23
  typescript_types_output: str
24
- typescript_routes_output: str
24
+ typescript_routes_output_by_endpoint: dict[str, str]
25
25
  typespec_files_input: list[str]
26
26
 
27
27
 
@@ -35,10 +35,9 @@ def get_python_api_file_path(
35
35
  def get_typescript_api_file_path(
36
36
  cross_output_paths: CrossOutputPaths,
37
37
  namespace: builder.SpecNamespace,
38
+ endpoint_key: builder.EndpointKey,
38
39
  ) -> str:
39
- return (
40
- f"{cross_output_paths.typescript_routes_output}/{'/'.join(namespace.path)}.tsx"
41
- )
40
+ return f"{cross_output_paths.typescript_routes_output_by_endpoint[endpoint_key]}/{'/'.join(namespace.path)}.tsx"
42
41
 
43
42
 
44
43
  def get_yaml_api_file_path(
@@ -68,13 +67,16 @@ def get_path_links(
68
67
  namespace: builder.SpecNamespace,
69
68
  *,
70
69
  current_path_type: str,
70
+ endpoint: builder.SpecEndpoint,
71
71
  ) -> str:
72
72
  if cross_output_paths is None:
73
73
  return ""
74
74
 
75
75
  api_paths = {
76
76
  "Python": get_python_api_file_path(cross_output_paths, namespace),
77
- "TypeScript": get_typescript_api_file_path(cross_output_paths, namespace),
77
+ "TypeScript": get_typescript_api_file_path(
78
+ cross_output_paths, namespace, endpoint.default_endpoint_key
79
+ ),
78
80
  "YAML": get_yaml_api_file_path(cross_output_paths, namespace),
79
81
  }
80
82
 
@@ -95,11 +97,11 @@ def get_path_links(
95
97
 
96
98
  if namespace.endpoint is not None:
97
99
  for (
98
- endpoint,
100
+ endpoint_key,
99
101
  path_specific_endpoint,
100
102
  ) in namespace.endpoint.path_per_api_endpoint.items():
101
103
  path_from_root = get_python_stub_file_path(path_specific_endpoint.function)
102
104
  if path_from_root is None:
103
105
  continue
104
- paths_string += f"{comment_prefix} Implementation for {endpoint}: file://./{return_to_root_path}{path_from_root}\n"
106
+ paths_string += f"{comment_prefix} Implementation for {endpoint_key}: file://./{return_to_root_path}{path_from_root}\n"
105
107
  return paths_string
@@ -261,6 +261,10 @@ def _emit_endpoint_parameters(
261
261
  } | _emit_endpoint_parameter_examples(examples)
262
262
 
263
263
 
264
+ def _emit_endpoint_deprecated(deprecated: bool) -> DictApiSchema:
265
+ return {"deprecated": True} if deprecated else {}
266
+
267
+
264
268
  def _emit_stability_level(
265
269
  stability_level: EmitOpenAPIStabilityLevel | None,
266
270
  ) -> DictApiSchema:
@@ -376,6 +380,7 @@ def _emit_namespace(
376
380
  "tags": endpoint.tags,
377
381
  "summary": endpoint.summary,
378
382
  }
383
+ | _emit_endpoint_deprecated(endpoint.deprecated)
379
384
  | _emit_endpoint_description(endpoint.description, ctx.endpoint.guides)
380
385
  | _emit_stability_level(endpoint.stability_level)
381
386
  | _emit_endpoint_parameters(endpoint, argument_type, ctx.endpoint.examples)
@@ -474,8 +479,9 @@ def _emit_type(
474
479
  return
475
480
 
476
481
  if isinstance(stype, builder.SpecTypeDefnUnion):
477
- ctx.types[stype.name] = open_api_type(
478
- ctx, stype.get_backing_type(), config=config
482
+ ctx.types[stype.name] = OpenAPIUnionType(
483
+ [open_api_type(ctx, p, config=config) for p in stype.types],
484
+ discrimnator=stype.discriminator,
479
485
  )
480
486
  return
481
487
 
@@ -617,6 +623,7 @@ def _emit_endpoint(
617
623
  tags=[tag_name],
618
624
  summary=f"{'/'.join(namespace.path[path_cutoff:])}",
619
625
  description=description,
626
+ deprecated=namespace.endpoint.deprecated,
620
627
  stability_level=namespace.endpoint.stability_level,
621
628
  examples=[
622
629
  EmitOpenAPIEndpointExample(
@@ -82,6 +82,7 @@ class EmitOpenAPIEndpoint:
82
82
  tags: list[str]
83
83
  summary: str
84
84
  description: str
85
+ deprecated: bool
85
86
  stability_level: EmitOpenAPIStabilityLevel | None
86
87
  examples: list[EmitOpenAPIEndpointExample]
87
88
  guides: list[EmitOpenAPIGuide]
@@ -357,7 +357,10 @@ def _emit_namespace(ctx: Context, namespace: builder.SpecNamespace) -> None:
357
357
  endpoint = namespace.endpoint
358
358
  if endpoint is not None:
359
359
  path_links = get_path_links(
360
- ctx.builder.cross_output_paths, namespace, current_path_type="Python"
360
+ ctx.builder.cross_output_paths,
361
+ namespace,
362
+ current_path_type="Python",
363
+ endpoint=endpoint,
361
364
  )
362
365
  if path_links != "":
363
366
  ctx.out.write("\n")
@@ -1,17 +1,18 @@
1
1
  import io
2
2
  import os
3
+ from typing import assert_never
3
4
 
4
5
  from . import builder, util
5
- from .builder import EndpointKey, EndpointSpecificPath
6
+ from .builder import EndpointKey, EndpointSpecificPath, PathMapping
6
7
  from .config import TypeScriptConfig
7
8
  from .cross_output_links import get_path_links
8
9
  from .emit_io_ts import emit_type_io_ts
9
10
  from .emit_typescript_util import (
10
11
  MODIFY_NOTICE,
11
12
  EmitTypescriptContext,
13
+ emit_constant_ts,
12
14
  emit_namespace_imports_ts,
13
15
  emit_type_ts,
14
- emit_value_ts,
15
16
  resolve_namespace_name,
16
17
  resolve_namespace_ref,
17
18
  ts_type_name,
@@ -37,6 +38,7 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
37
38
  out=io.StringIO(),
38
39
  namespace=namespace,
39
40
  cross_output_paths=builder.cross_output_paths,
41
+ api_endpoints=builder.api_endpoints,
40
42
  )
41
43
 
42
44
  _emit_namespace(ctx, config, namespace)
@@ -78,6 +80,7 @@ def _emit_types(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
78
80
  full.write("\n")
79
81
  full.write(MODIFY_NOTICE)
80
82
  full.write(f"// === START section from {namespace.name}.ts.part ===\n")
83
+ full.write("\n")
81
84
  full.write(part)
82
85
  full.write(f"// === END section from {namespace.name}.ts.part ===\n")
83
86
 
@@ -112,7 +115,7 @@ def _emit_namespace(
112
115
  emit_type_ts(ctx, stype)
113
116
 
114
117
  for sconst in namespace.constants.values():
115
- _emit_constant(ctx, sconst)
118
+ emit_constant_ts(ctx, sconst)
116
119
 
117
120
  if namespace.endpoint is not None:
118
121
  _emit_endpoint(ctx, config, namespace, namespace.endpoint)
@@ -145,7 +148,10 @@ def _emit_endpoint(
145
148
  assert endpoint.result_type == builder.ResultType.json
146
149
 
147
150
  paths_string = get_path_links(
148
- ctx.cross_output_paths, namespace, current_path_type="TypeScript"
151
+ ctx.cross_output_paths,
152
+ namespace,
153
+ current_path_type="TypeScript",
154
+ endpoint=endpoint,
149
155
  )
150
156
 
151
157
  data_loader_head = ""
@@ -155,7 +161,7 @@ def _emit_endpoint(
155
161
  assert has_data
156
162
 
157
163
  data_loader_head = (
158
- 'import { buildApiDataLoader, argsKey } from "unc_base/data_manager"\n'
164
+ 'import { argsKey, buildApiDataLoader } from "unc_base/data_manager"\n'
159
165
  )
160
166
  data_loader_body = (
161
167
  "\nexport const data = buildApiDataLoader(argsKey(), apiCall)\n"
@@ -175,38 +181,56 @@ def _emit_endpoint(
175
181
  unc_base_api_imports = (
176
182
  f"appSpecificApiPath, {wrap_name}" if has_multiple_endpoints else wrap_name
177
183
  )
184
+ path_mapping = ctx.api_endpoints[endpoint.default_endpoint_key].path_mapping
185
+
186
+ match path_mapping:
187
+ case PathMapping.NO_MAPPING:
188
+ path_mapping_part = (
189
+ "\n { pathMapping: ApplicationT.APIPathMapping.noMapping },"
190
+ )
191
+ case PathMapping.DEFAULT_MAPPING:
192
+ path_mapping_part = ""
193
+ case _:
194
+ assert_never(path_mapping)
195
+
178
196
  unc_types_imports = (
179
- 'import { ApplicationT } from "unc_types"\n' if has_multiple_endpoints else ""
197
+ 'import { ApplicationT } from "unc_types"\n'
198
+ if has_multiple_endpoints or path_mapping_part != ""
199
+ else ""
180
200
  )
181
201
 
182
202
  type_path = f"unc_types/{'/'.join(namespace.path)}"
183
203
 
184
204
  if is_binary:
185
- tsx_response_part = f"""import {{ {unc_base_api_imports} }} from "unc_base/api"
186
- import type {{ Arguments }} from "{type_path}"
187
- {unc_types_imports}
205
+ tsx_response_head = f"""import {{ {unc_base_api_imports} }} from "unc_base/api"
206
+ """
207
+ tsx_response_part = f"""import type {{ Arguments }} from "{type_path}"
208
+
188
209
  export type {{ Arguments }}
189
210
  """
190
211
  elif has_data and endpoint.has_attachment:
191
- tsx_response_part = f"""import {{ {unc_base_api_imports}, type AttachmentResponse }} from "unc_base/api"
192
- import type {{ Arguments, Data }} from "{type_path}"
193
- {unc_types_imports}
212
+ tsx_response_head = f"""import {{ type AttachmentResponse, {unc_base_api_imports} }} from "unc_base/api"
213
+ """
214
+ tsx_response_part = f"""import type {{ Arguments, Data }} from "{type_path}"
215
+
194
216
  export type {{ Arguments, Data }}
195
217
  export type Response = AttachmentResponse<Data>
196
218
  """
197
219
  elif has_data:
198
- tsx_response_part = f"""import {{ {unc_base_api_imports}, type JsonResponse }} from "unc_base/api"
199
- import type {{ Arguments, Data }} from "{type_path}"
200
- {unc_types_imports}
220
+ tsx_response_head = f"""import {{ {unc_base_api_imports}, type JsonResponse }} from "unc_base/api"
221
+ """
222
+ tsx_response_part = f"""import type {{ Arguments, Data }} from "{type_path}"
223
+
201
224
  export type {{ Arguments, Data }}
202
225
  export type Response = JsonResponse<Data>
203
226
  """
204
227
 
205
228
  else:
206
229
  assert has_deprecated_result
207
- tsx_response_part = f"""import {{ {unc_base_api_imports} }} from "unc_base/api"
208
- import type {{ Arguments, DeprecatedResult }} from "{type_path}"
209
- {unc_types_imports}
230
+ tsx_response_head = f"""import {{ {unc_base_api_imports} }} from "unc_base/api"
231
+ """
232
+ tsx_response_part = f"""import type {{ Arguments, DeprecatedResult }} from "{type_path}"
233
+
210
234
  export type {{ Arguments }}
211
235
  export type Response = DeprecatedResult
212
236
  """
@@ -247,18 +271,18 @@ export type Response = DeprecatedResult
247
271
 
248
272
  # tsx_api = f"""{MODIFY_NOTICE}
249
273
  tsx_api = f"""{MODIFY_NOTICE}{paths_string}
250
- {data_loader_head}{tsx_response_part}
274
+ {tsx_response_head}{data_loader_head}{unc_types_imports}{tsx_response_part}
251
275
  export const apiCall = {wrap_call}(
252
- {endpoint_path_part}
276
+ {endpoint_path_part}{path_mapping_part}
253
277
  )
254
278
  {data_loader_body}"""
255
279
 
256
- output = f"{config.routes_output}/{'/'.join(namespace.path)}.tsx"
280
+ output = f"{config.endpoint_to_routes_output[endpoint.default_endpoint_key]}/{'/'.join(namespace.path)}.tsx"
257
281
  util.rewrite_file(output, tsx_api)
258
282
 
259
283
  # Hacky index support, until enough is migrated to regen entirely
260
284
  # Emits the import into the UI API index file
261
- index_path = f"{config.routes_output}/{'/'.join(namespace.path[0:-1])}/index.tsx"
285
+ index_path = f"{config.endpoint_to_routes_output[endpoint.default_endpoint_key]}/{'/'.join(namespace.path[0:-1])}/index.tsx"
262
286
  api_name = f"Api{ts_type_name(namespace.path[0 - 1])}"
263
287
  if os.path.exists(index_path):
264
288
  with open(index_path) as index:
@@ -274,14 +298,6 @@ export const apiCall = {wrap_call}(
274
298
  index.write(f"export {{ {api_name} }}\n")
275
299
 
276
300
 
277
- def _emit_constant(ctx: EmitTypescriptContext, sconst: builder.SpecConstant) -> None:
278
- ctx.out.write("\n\n")
279
- ctx.out.write(MODIFY_NOTICE)
280
- value = emit_value_ts(ctx, sconst.value_type, sconst.value)
281
- const_name = sconst.name.upper()
282
- ctx.out.write(f"export const {const_name} = {value}\n")
283
-
284
-
285
301
  def _emit_id_source(builder: builder.SpecBuilder, config: TypeScriptConfig) -> None:
286
302
  id_source_output = config.id_source_output
287
303
  if id_source_output is None:
@@ -32,6 +32,7 @@ class EmitTypescriptContext:
32
32
  namespace: builder.SpecNamespace
33
33
  namespaces: set[builder.SpecNamespace] = field(default_factory=set)
34
34
  cross_output_paths: CrossOutputPaths | None = None
35
+ api_endpoints: dict[builder.EndpointKey, builder.APIEndpointInfo]
35
36
 
36
37
 
37
38
  def ts_type_name(name: str) -> str:
@@ -80,6 +81,12 @@ def emit_value_ts(
80
81
  if stype.defn_type.is_base_type(builder.BaseTypeName.s_dict):
81
82
  key_type = stype.parameters[0]
82
83
  value_type = stype.parameters[1]
84
+
85
+ if not key_type.is_base_type(
86
+ builder.BaseTypeName.s_string
87
+ ) and not isinstance(key_type, builder.SpecTypeDefnStringEnum):
88
+ raise Exception("invalid dict keys -- dict keys must be string or enum")
89
+
83
90
  return (
84
91
  "{\n\t"
85
92
  + ",\n\t".join(
@@ -106,6 +113,14 @@ def emit_value_ts(
106
113
  raise Exception("invalid constant type", value, stype, type(stype))
107
114
 
108
115
 
116
+ def emit_constant_ts(ctx: EmitTypescriptContext, sconst: builder.SpecConstant) -> None:
117
+ ctx.out.write("\n\n")
118
+ ctx.out.write(MODIFY_NOTICE)
119
+ value = emit_value_ts(ctx, sconst.value_type, sconst.value)
120
+ const_name = sconst.name.upper()
121
+ ctx.out.write(f"export const {const_name} = {value}\n")
122
+
123
+
109
124
  def emit_type_ts(ctx: EmitTypescriptContext, stype: builder.SpecType) -> None:
110
125
  if not isinstance(stype, builder.SpecTypeDefn):
111
126
  return
@@ -118,6 +133,7 @@ def emit_type_ts(ctx: EmitTypescriptContext, stype: builder.SpecType) -> None:
118
133
 
119
134
  if isinstance(stype, builder.SpecTypeDefnExternal):
120
135
  assert not stype.is_exported, "expecting private names"
136
+ ctx.out.write("\n")
121
137
  ctx.out.write(stype.external_map["ts"])
122
138
  ctx.out.write("\n")
123
139
  return
@@ -46,7 +46,7 @@ def load_types(config: Config) -> SpecBuilder | None:
46
46
  cross_output_paths = CrossOutputPaths(
47
47
  python_types_output=config.python.types_output,
48
48
  typescript_types_output=config.typescript.types_output,
49
- typescript_routes_output=config.typescript.routes_output,
49
+ typescript_routes_output_by_endpoint=config.typescript.endpoint_to_routes_output,
50
50
  typespec_files_input=config.type_spec_types,
51
51
  # IMPROVE not sure how to know which one is the correct one in emit_typescript
52
52
  )
@@ -223,13 +223,21 @@ class OpenAPIUnionType(OpenAPIType):
223
223
  base_types: list[OpenAPIType],
224
224
  description: str | None = None,
225
225
  nullable: bool = False,
226
+ discrimnator: str | None = None,
227
+ discriminator_map: dict[str, OpenAPIType] | None = None,
226
228
  ) -> None:
227
229
  self.base_types = base_types
230
+ self._discriminator = discrimnator
228
231
  super().__init__(description=description, nullable=nullable)
229
232
 
230
233
  def asdict(self) -> dict[str, object]:
231
234
  # TODO: use parents description and nullable
232
- return {"oneOf": [base_type.asdict() for base_type in self.base_types]}
235
+ return {
236
+ "oneOf": [base_type.asdict() for base_type in self.base_types],
237
+ "discriminator": {"propertyName": self._discriminator}
238
+ if self._discriminator is not None
239
+ else None,
240
+ }
233
241
 
234
242
 
235
243
  class OpenAPIIntersectionType(OpenAPIType):
@@ -3,6 +3,7 @@
3
3
  // doesn't allow referring explicitly to global names (thus cannot override here)
4
4
  // IMPROVE: invert relationship for global.d.ts looks here instead
5
5
  import * as IO from 'io-ts';
6
+
6
7
  type localJsonScalar = JsonScalar
7
8
  type localJsonValue = JsonValue
8
9
  type localObjectId = ObjectId
@@ -282,6 +282,7 @@ def generate_entry_actions_typescript(
282
282
  ctx = emit_typescript_util.EmitTypescriptContext(
283
283
  out=definition_buffer,
284
284
  namespace=index_namespace,
285
+ api_endpoints={},
285
286
  )
286
287
  builder.namespaces[index_namespace.name] = index_namespace
287
288
 
@@ -35,6 +35,7 @@ class Arguments:
35
35
  definition_key: identifier_t.IdentifierKey
36
36
  field_values: list[field_values_t.FieldArgumentValue]
37
37
  entity_key: identifier_t.IdentifierKey | None = None
38
+ on_create_init_field_values: list[field_values_t.FieldArgumentValue] | None = None
38
39
 
39
40
 
40
41
  # DO NOT MODIFY -- This file is generated by type_spec
@@ -258,10 +258,12 @@ class AsyncBatchProcessorBase(ABC):
258
258
  definition_key: identifier_t.IdentifierKey,
259
259
  field_values: list[field_values_t.FieldArgumentValue],
260
260
  entity_key: identifier_t.IdentifierKey | None = None,
261
+ on_create_init_field_values: list[field_values_t.FieldArgumentValue] | None = None,
261
262
  depends_on: list[str] | None = None,
262
263
  ) -> async_batch_t.QueuedAsyncBatchRequest:
263
264
  """Creates or updates field values for an entity
264
265
 
266
+ :param on_create_init_field_values: Field values set only when the entity is created (will be ignored if entity already exists)
265
267
  :param depends_on: A list of batch reference keys to process before processing this request
266
268
  """
267
269
  args = create_or_update_entity_t.Arguments(
@@ -269,6 +271,7 @@ class AsyncBatchProcessorBase(ABC):
269
271
  entity_type=entity_type,
270
272
  definition_key=definition_key,
271
273
  field_values=field_values,
274
+ on_create_init_field_values=on_create_init_field_values,
272
275
  )
273
276
  json_data = serialize_for_api(args)
274
277
 
@@ -412,15 +412,18 @@ class ClientMethods(ABC):
412
412
  definition_key: identifier_t.IdentifierKey,
413
413
  field_values: list[field_values_t.FieldArgumentValue],
414
414
  entity_key: identifier_t.IdentifierKey | None = None,
415
+ on_create_init_field_values: list[field_values_t.FieldArgumentValue] | None = None,
415
416
  ) -> create_or_update_entity_t.Data:
416
417
  """Creates or updates field values for an entity
417
418
 
419
+ :param on_create_init_field_values: Field values set only when the entity is created (will be ignored if entity already exists)
418
420
  """
419
421
  args = create_or_update_entity_t.Arguments(
420
422
  entity_key=entity_key,
421
423
  entity_type=entity_type,
422
424
  definition_key=definition_key,
423
425
  field_values=field_values,
426
+ on_create_init_field_values=on_create_init_field_values,
424
427
  )
425
428
  api_request = APIRequest(
426
429
  method=create_or_update_entity_t.ENDPOINT_METHOD,
@@ -42,6 +42,7 @@ __all__: list[str] = [
42
42
  "condition_match": "Condition Match",
43
43
  "condition_parameter": "Condition Parameter",
44
44
  "condition_parameter_mat_family": "Condition Parameter Material Family",
45
+ "condition_parameter_matches": "Condition Parameter Matches",
45
46
  "condition_parameter_rule": "Condition Parameter Rule",
46
47
  "condition_parameter_value": "Condition Parameter Value",
47
48
  "constraint": "Constraint",
@@ -110,6 +111,7 @@ __all__: list[str] = [
110
111
  "output_calculation_entity_mapping": "Output Calculation Entity Mapping",
111
112
  "output_category_all": "Output Category",
112
113
  "output_condition": "Output Condition",
114
+ "output_condition_condition_parameter": "Output Condition Condition Parameter",
113
115
  "output_default_condition": "Output Default Condition",
114
116
  "output_condition_parameter": "Output Condition Parameter",
115
117
  "output_condition_parameter_analytical_method_category": "Output Condition Parameter Analytical Method Category",
@@ -138,6 +140,7 @@ __all__: list[str] = [
138
140
  "recipe_ingredient_actual": "Recipe Ingredient Actual",
139
141
  "recipe_ingredients_compounded": "Recipe Ingredients Compounded",
140
142
  "recipe_ingredients_compounded_calculation": "Recipe Ingredients Compounded Calculation",
143
+ "recipe_link": "Experiment Link",
141
144
  "recipe_output": "Recipe Output",
142
145
  "recipe_output_annotation": "Recipe Output Annotation",
143
146
  "recipe_output_metadata": "Recipe Output Metadata",
@@ -224,6 +227,7 @@ class EntityType(StrEnum):
224
227
  CONDITION_MATCH = "condition_match"
225
228
  CONDITION_PARAMETER = "condition_parameter"
226
229
  CONDITION_PARAMETER_MAT_FAMILY = "condition_parameter_mat_family"
230
+ CONDITION_PARAMETER_MATCHES = "condition_parameter_matches"
227
231
  CONDITION_PARAMETER_RULE = "condition_parameter_rule"
228
232
  CONDITION_PARAMETER_VALUE = "condition_parameter_value"
229
233
  CONSTRAINT = "constraint"
@@ -292,6 +296,7 @@ class EntityType(StrEnum):
292
296
  OUTPUT_CALCULATION_ENTITY_MAPPING = "output_calculation_entity_mapping"
293
297
  OUTPUT_CATEGORY_ALL = "output_category_all"
294
298
  OUTPUT_CONDITION = "output_condition"
299
+ OUTPUT_CONDITION_CONDITION_PARAMETER = "output_condition_condition_parameter"
295
300
  OUTPUT_DEFAULT_CONDITION = "output_default_condition"
296
301
  OUTPUT_CONDITION_PARAMETER = "output_condition_parameter"
297
302
  OUTPUT_CONDITION_PARAMETER_ANALYTICAL_METHOD_CATEGORY = "output_condition_parameter_analytical_method_category"
@@ -320,6 +325,7 @@ class EntityType(StrEnum):
320
325
  RECIPE_INGREDIENT_ACTUAL = "recipe_ingredient_actual"
321
326
  RECIPE_INGREDIENTS_COMPOUNDED = "recipe_ingredients_compounded"
322
327
  RECIPE_INGREDIENTS_COMPOUNDED_CALCULATION = "recipe_ingredients_compounded_calculation"
328
+ RECIPE_LINK = "recipe_link"
323
329
  RECIPE_OUTPUT = "recipe_output"
324
330
  RECIPE_OUTPUT_ANNOTATION = "recipe_output_annotation"
325
331
  RECIPE_OUTPUT_METADATA = "recipe_output_metadata"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.115
3
+ Version: 0.0.116
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,11 @@ examples/upload_files.py,sha256=qMaSvMSdTMPOOP55y1AwEurc0SOdZAMvEydlqJPsGpg,432
26
26
  examples/integration-server/pyproject.toml,sha256=i4Px7I__asDvP4WlAd2PncfRRQ-U4t5xp0tqT9YYs3s,9149
27
27
  examples/integration-server/jobs/materials_auto/concurrent_cron.py,sha256=xsK3H9ZEaniedC2nJUB0rqOcFI8y-ojfl_nLSJb9AMM,312
28
28
  examples/integration-server/jobs/materials_auto/example_cron.py,sha256=7VVQ-UJsq3DbGpN3XPnorRVZYo-vCwbfSU3VVDluIzA,699
29
- examples/integration-server/jobs/materials_auto/example_http.py,sha256=h97_IBC5EQiAUA4A5xyPpgFIqPTZWKIhMpmVAgVZEBE,941
29
+ examples/integration-server/jobs/materials_auto/example_http.py,sha256=eVq-Fss_AhmztxOMqqO-GYGF3KvPt1O5HbNwwC2arh8,1037
30
+ examples/integration-server/jobs/materials_auto/example_instrument.py,sha256=6qq6a8S5soKC-ypVswZEhkLzB_mxd4dxCSIoXKrbGDs,1261
30
31
  examples/integration-server/jobs/materials_auto/example_runsheet_wh.py,sha256=_wILTnbzzLf9zrcQb_KQKytxxcya1ej6MqQnoUSS4fA,1180
31
32
  examples/integration-server/jobs/materials_auto/example_wh.py,sha256=PN-skP27yJwDZboWk5g5EZEc3AKfVayQLfnopjsDKJc,659
32
- examples/integration-server/jobs/materials_auto/profile.yaml,sha256=MNKRn09iaiNF8dxOZ7Y6558UW6aCZ-9l9hQAwzYN8zs,1685
33
+ examples/integration-server/jobs/materials_auto/profile.yaml,sha256=btUdn8hStM6Zp4zr0kBI2lL461MqDdzfSuF4LvuSQ8k,1926
33
34
  pkgs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
35
  pkgs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
36
  pkgs/argument_parser/__init__.py,sha256=VWUOOtJ-ueRF2lkIJzgQe4xhBKR9IPkgf9vY28nF35s,870
@@ -63,29 +64,29 @@ pkgs/strenum_compat/__init__.py,sha256=wXRFeNvBm8RU6dy1PFJ5sRLgUIEeH_DVR95Sv5qpG
63
64
  pkgs/strenum_compat/strenum_compat.py,sha256=uOUAgpYTjHs1MX8dG81jRlyTkt3KNbkV_25zp7xTX2s,36
64
65
  pkgs/type_spec/__init__.py,sha256=h5DmJTca4QVV10sZR1x0-MlkZfuGYDfapR3zHvXfzto,19
65
66
  pkgs/type_spec/__main__.py,sha256=5bJaX9Y_-FavP0qwzhk-z-V97UY7uaezJTa1zhO_HHQ,1048
66
- pkgs/type_spec/builder.py,sha256=XqkKO-GxV2DLS_iDN9tnQJfNcefz5yMAwyjnMog87jE,54049
67
- pkgs/type_spec/config.py,sha256=K6WebgeI3Saew0IEBcm1s2fauw_CyvH183emVrNoUXg,5327
68
- pkgs/type_spec/cross_output_links.py,sha256=bVNn0a4LMVTRLg_zjtiHnoTwdINHfftjWoH6tGdxhlk,3124
67
+ pkgs/type_spec/builder.py,sha256=17_hkJI5jDb_IGOHZCiZDJ8_er-amVH0-WRpqJb7hEE,54365
68
+ pkgs/type_spec/config.py,sha256=m0Rky7Rg2jMglDPQChF30p5h5P86Ap1GObwzLzmypNE,5829
69
+ pkgs/type_spec/cross_output_links.py,sha256=ttFNfuQmR3sNnPSeUER5IPgLiYc-FB5gjlf7RyFYMpc,3293
69
70
  pkgs/type_spec/emit_io_ts.py,sha256=CUvBs0boB_X-Kndh66yYcqFfq3oC_LGs8YffLkJ0ZXA,5707
70
- pkgs/type_spec/emit_open_api.py,sha256=B9cGFR7TU90_yky-HdNq1sDIJOuP3eU4o3j7nNgIpkU,26047
71
- pkgs/type_spec/emit_open_api_util.py,sha256=xnc4ymNzEyAS1Q2cV6Ma9Y6mQ1MbPPi2WaHKTSFETr8,2346
72
- pkgs/type_spec/emit_python.py,sha256=JCT_o6sPJRaAL1J-TlMT-RN8d4bzLcYJF2iwNTcGlBA,52651
73
- pkgs/type_spec/emit_typescript.py,sha256=0HRzxlbIP91rzbVkAntF4TKZppoKcWsqnDLAIRc1bng,10927
74
- pkgs/type_spec/emit_typescript_util.py,sha256=pYhzRb-U-B5peWdfJDQ0i9kI80Ojf2wbfkvJutk9rTw,10975
75
- pkgs/type_spec/load_types.py,sha256=GndEKQtICCQi4oXsL6cZ9khm8lBB830e6hx0wML4dHs,4278
71
+ pkgs/type_spec/emit_open_api.py,sha256=5M0lAEbjm0bRPjuGpChMS1eB4oCkb2Hd3e7mr-rLv0Y,26345
72
+ pkgs/type_spec/emit_open_api_util.py,sha256=bTmRvrGP82-eB75hwf9ySI7pDEC87FNQTF18VKEWSXY,2367
73
+ pkgs/type_spec/emit_python.py,sha256=aURsc-wWdamVDCrIWxA7s8_MLAMjLdXZor6ykkibzXY,52707
74
+ pkgs/type_spec/emit_typescript.py,sha256=FINir79bz4tJYgJuUylNJFvqChzaFlHNCfZ5D7A6B1I,11447
75
+ pkgs/type_spec/emit_typescript_util.py,sha256=ChP4oF2ZJoL0qErGCL0nscj0w_yH6TBgE92MtQS8nPI,11638
76
+ pkgs/type_spec/load_types.py,sha256=JL7tX2H_cy3p5HjGuvNFJlY4pDSbDVnYFsh9mK16-ic,4302
76
77
  pkgs/type_spec/non_discriminated_union_exceptions.py,sha256=JB4WNDJWc3e9WMOabX4aTd0-6K7n1hctIW2lGf1bYts,612
77
- pkgs/type_spec/open_api_util.py,sha256=DYnlygaMIqDQtSuYpUpd5lpA9JG4JHd_-iGe-BY2lhw,7333
78
+ pkgs/type_spec/open_api_util.py,sha256=muEX3hYIhlLFA9XDfMruk2687w6bKrZnluIVVqEtDao,7642
78
79
  pkgs/type_spec/test.py,sha256=4ueujBq-pEgnX3Z69HyPmD-bullFXmpixcpVzfOkhP4,489
79
80
  pkgs/type_spec/util.py,sha256=S_SGTJU192x-wIbngVUTvXhQENMbBfxluigLmnItGI8,4848
80
81
  pkgs/type_spec/actions_registry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
82
  pkgs/type_spec/actions_registry/__main__.py,sha256=SRw6kIhHTW7W2wGijYq66JARzoc4KpPmbLqwvnETyTE,4277
82
83
  pkgs/type_spec/actions_registry/emit_typescript.py,sha256=W1lI36ITdJ7MBf37wlTB7H3X9Ljt217vIGMv4e3fxfY,5986
83
84
  pkgs/type_spec/parts/base.py.prepart,sha256=Xy8my5ol_Iu0hpQpvgsmqGLkGcMsLSg-cgjm4Yp-QI4,2369
84
- pkgs/type_spec/parts/base.ts.prepart,sha256=2FJJvpg2olCcavxj0nbYWdwKl6KeScour2JjSvN42l8,1001
85
+ pkgs/type_spec/parts/base.ts.prepart,sha256=42-1_N_K04t4c6pE62V4wBw3bR5bgPxhmXUk__A7gAs,1002
85
86
  pkgs/type_spec/type_info/__main__.py,sha256=TLNvCHGcmaj_8Sj5bAQNpuNaaw2dpDzoFDWZds0V4Qo,1002
86
87
  pkgs/type_spec/type_info/emit_type_info.py,sha256=xRjZiwDDii4Bq8yVfcgE8YFechoKAcGmYXBk3Dq-K-s,15387
87
88
  pkgs/type_spec/ui_entry_actions/__init__.py,sha256=WiHE_BexOEZWbkkbD7EnFau1aMLNmfgQywG9PTQNCkw,135
88
- pkgs/type_spec/ui_entry_actions/generate_ui_entry_actions.py,sha256=IPBdVfJReLLGVaZOkb0QYGGrm73JqMXuAGSbeoBVbDg,9477
89
+ pkgs/type_spec/ui_entry_actions/generate_ui_entry_actions.py,sha256=65qUEp9zVcAsHEe3QjOTlPfLf45kH980fOXZXKNmOC8,9503
89
90
  pkgs/type_spec/value_spec/__init__.py,sha256=Z-grlcZtxAfEXhPHsK0nD7PFLGsv4eqvunaPN7_TA84,83
90
91
  pkgs/type_spec/value_spec/__main__.py,sha256=oM5lcV6Hv_03okjtfWn2fzSHsarFVa9ArU_g02XnQJw,8879
91
92
  pkgs/type_spec/value_spec/convert_type.py,sha256=OvP7dwUMHXNHVXWYT4jkaYJ96S3a2SnFuC_iMdYVB7s,2927
@@ -141,7 +142,7 @@ uncountable/integration/secret_retrieval/retrieve_secret.py,sha256=LBEf18KHtXZxg
141
142
  uncountable/integration/webhook_server/entrypoint.py,sha256=NQawXl_JCRojdVniS5RF7dobQQKW_Wy03bwy-uXknuA,3441
142
143
  uncountable/types/__init__.py,sha256=eqeDMCXTr9Mwo10RSGMa4znfu_7TVp_0gYJxPKmLCfQ,9990
143
144
  uncountable/types/async_batch.py,sha256=yCCWrrLQfxXVqZp-KskxLBNkNmuELdz4PJjx8ULppgs,662
144
- uncountable/types/async_batch_processor.py,sha256=Y8rp-GtuhwUBg18yb5T7bQpb48vsQpACGrvaIiFYLrU,21765
145
+ uncountable/types/async_batch_processor.py,sha256=h_8Snzt3lbEFlZAZFByt4Hg4dv2YlxMijHjTHjZ0aXY,22062
145
146
  uncountable/types/async_batch_t.py,sha256=JuswurXlYW38MfAXJ0UWb7hE2rmzFaHBAsNhRYAyMD4,3779
146
147
  uncountable/types/async_jobs.py,sha256=JI0ScfawaqMRbJ2jbgW3YQLhijPnBeYdMnZJjygSxHg,322
147
148
  uncountable/types/async_jobs_t.py,sha256=u4xd3i512PZ-9592Q2ZgWh_faMiI4UMm0F_gOmZnerI,1389
@@ -153,7 +154,7 @@ uncountable/types/calculations.py,sha256=fApOFpgBemt_t7IVneVR0VdI3X5EOxiG6Xhzr6R
153
154
  uncountable/types/calculations_t.py,sha256=pl-lhjyDQuj11Sf9g1-0BsSkN7Ez8UxDp8-KMQ_3enM,709
154
155
  uncountable/types/chemical_structure.py,sha256=ujyragaD26-QG5jgKnWhO7TN3N1V9b_04T2WhqNYxxo,281
155
156
  uncountable/types/chemical_structure_t.py,sha256=VFFyits_vx4t5L2euu_qFiSpsGJjURkDPr3ISnr3nPc,855
156
- uncountable/types/client_base.py,sha256=m4AI0E4ET-FFmewHicW1t2oayraIhS_VYMuyTCnOk1g,76085
157
+ uncountable/types/client_base.py,sha256=Qd8kxA0C76FKTAuoJOVjEw48mInfV_IXH2CBBTyYwAs,76382
157
158
  uncountable/types/client_config.py,sha256=qLpHt4O_B098CyN6qQajoxZ2zjZ1DILXLUEGyyGP0TQ,280
158
159
  uncountable/types/client_config_t.py,sha256=yTFIYAitMrcc4oV9J-HADODS_Hwi45z-piz7rr7QT04,781
159
160
  uncountable/types/curves.py,sha256=QyEyC20jsG-LGKVx6miiF-w70vKMwNkILFBDIJ5Ok9g,345
@@ -161,7 +162,7 @@ uncountable/types/curves_t.py,sha256=DxYepdC3QKKR7mepOOBoyarNcFZQdUa5ZYH-hwCY3BI
161
162
  uncountable/types/data.py,sha256=u2isf4XEug3Eu-xSIoqGaCQmW2dFaKBHCkP_WKYwwBc,500
162
163
  uncountable/types/data_t.py,sha256=vFoypK_WMGfN28r1sSlDYHZNUdBQC0XCN7-_Mlo4FJk,2832
163
164
  uncountable/types/entity.py,sha256=Zclk1LYcRaYrMDhqyCjMSLEg0fE6_q8LHvV22Qvscgs,566
164
- uncountable/types/entity_t.py,sha256=I_dJ08Wd7NsVFkZx3p9-VAARx8nCkLJCtY--hv0zR8c,20288
165
+ uncountable/types/entity_t.py,sha256=Q-Ji3IMpQxXoY680ZOYz5Zkcy_wrz3lgQOnKqoU9noA,20666
165
166
  uncountable/types/experiment_groups.py,sha256=qUpFOx1AKgzaT_4khCOv5Xs6jwiQGbvHH-GUh3v1nv4,288
166
167
  uncountable/types/experiment_groups_t.py,sha256=29Ct-WPejpYMuGfnFfOoosU9iSfjzxpabpBX6oTPFUA,761
167
168
  uncountable/types/exports.py,sha256=VMmxUO2PpV1Y63hZ2AnVor4H-B6aswJ7YpSru_u89lU,334
@@ -235,7 +236,7 @@ uncountable/types/api/condition_parameters/upsert_condition_match.py,sha256=7I9l
235
236
  uncountable/types/api/entity/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
236
237
  uncountable/types/api/entity/create_entities.py,sha256=cCDEra2SHvGWvz7nIxxMDSQN6OWrHMTT0JSomWUesto,1794
237
238
  uncountable/types/api/entity/create_entity.py,sha256=urT6C7iGAa7_rCv9Wcz6GM_lKg1tP55E__rjNkj-Rjc,1879
238
- uncountable/types/api/entity/create_or_update_entity.py,sha256=OK05B9nqlxsCU41iVCI_Nn66qVeQfqgdf2oZn7kUPFM,1445
239
+ uncountable/types/api/entity/create_or_update_entity.py,sha256=cxjJIcZTKOg8Y5kGzctYKayfnr8BNZDOM5YfI4dBSf0,1532
239
240
  uncountable/types/api/entity/export_entities.py,sha256=zz_4P6bQAt7gU2o2to9zUh0HHLQKaxLkbFGfbgY3KVk,1395
240
241
  uncountable/types/api/entity/get_entities_data.py,sha256=hu0UfkU4PTyv3_CBZ7YmR8L8BKMq8hx6zH43XtUm16E,1616
241
242
  uncountable/types/api/entity/grant_entity_permissions.py,sha256=4CvVIMvpdok8K1Bh6wMlwuUmoeP_-nL9y2GCEM6uAhY,1536
@@ -318,7 +319,7 @@ uncountable/types/api/triggers/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr
318
319
  uncountable/types/api/triggers/run_trigger.py,sha256=dgDX_sRWSJ36UuzMZhG25oHV1HIOUKYY2G3fjKugZrw,1204
319
320
  uncountable/types/api/uploader/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
320
321
  uncountable/types/api/uploader/invoke_uploader.py,sha256=Bj7Dq4A90k00suacwk3bLA_dCb2aovS1kAbVam2AQnM,1395
321
- uncountablepythonsdk-0.0.115.dist-info/METADATA,sha256=-CVaJt1Lh0NBrGUWB8G7L3jEsniPCdVd_1un50_IUQo,2143
322
- uncountablepythonsdk-0.0.115.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
323
- uncountablepythonsdk-0.0.115.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
324
- uncountablepythonsdk-0.0.115.dist-info/RECORD,,
322
+ uncountablepythonsdk-0.0.116.dist-info/METADATA,sha256=oPQJIEgmWPjJGw_pV9kIAdtXYNfSegMl15O4xPvJ080,2143
323
+ uncountablepythonsdk-0.0.116.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
324
+ uncountablepythonsdk-0.0.116.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
325
+ uncountablepythonsdk-0.0.116.dist-info/RECORD,,