UncountablePythonSDK 0.0.193__py3-none-any.whl → 0.0.194__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.
- examples/integration-server/pyproject.toml +1 -1
- pkgs/argument_parser/__init__.py +2 -0
- pkgs/type_spec/builder.py +66 -9
- pkgs/type_spec/builder_types.py +0 -6
- pkgs/type_spec/emit_open_api.py +50 -33
- pkgs/type_spec/emit_open_api_util.py +1 -0
- pkgs/type_spec/emit_python.py +149 -194
- pkgs/type_spec/emit_typescript.py +3 -2
- pkgs/type_spec/python/__init__.py +14 -0
- pkgs/type_spec/python/dataclass_fields.py +9 -0
- pkgs/type_spec/python/names.py +33 -0
- pkgs/type_spec/python/serial_class_options.py +45 -0
- pkgs/type_spec/type_info/emit_type_info.py +1 -1
- pkgs/type_spec/value_spec/emit_python.py +2 -2
- uncountable/types/__init__.py +4 -0
- uncountable/types/api/notebooks/add_notebook_content.py +1 -1
- uncountable/types/api/notebooks/clear_notebook_content.py +83 -0
- uncountable/types/api/recipes/remove_recipe_workflow_step.py +61 -0
- uncountable/types/async_batch_processor.py +73 -0
- uncountable/types/async_batch_t.py +2 -0
- uncountable/types/client_base.py +51 -2
- uncountable/types/entity_t.py +4 -0
- {uncountablepythonsdk-0.0.193.dist-info → uncountablepythonsdk-0.0.194.dist-info}/METADATA +2 -2
- {uncountablepythonsdk-0.0.193.dist-info → uncountablepythonsdk-0.0.194.dist-info}/RECORD +26 -21
- {uncountablepythonsdk-0.0.193.dist-info → uncountablepythonsdk-0.0.194.dist-info}/WHEEL +1 -1
- pkgs/codeowners.py +0 -157
- {uncountablepythonsdk-0.0.193.dist-info → uncountablepythonsdk-0.0.194.dist-info}/top_level.txt +0 -0
pkgs/argument_parser/__init__.py
CHANGED
|
@@ -19,6 +19,7 @@ __all__ = [
|
|
|
19
19
|
"is_string_enum_class",
|
|
20
20
|
"is_union",
|
|
21
21
|
"kebab_to_pascal_case",
|
|
22
|
+
"parse_fallback_legacy_type",
|
|
22
23
|
"resolve_serialized_field_name",
|
|
23
24
|
"snake_to_camel_case",
|
|
24
25
|
]
|
|
@@ -36,6 +37,7 @@ from .case_convert import (
|
|
|
36
37
|
from .field_name_resolution import (
|
|
37
38
|
resolve_serialized_field_name as resolve_serialized_field_name,
|
|
38
39
|
)
|
|
40
|
+
from .parse_fallback import parse_fallback_legacy_type as parse_fallback_legacy_type
|
|
39
41
|
from .parser_base import ParserBase as ParserBase
|
|
40
42
|
from .parser_builder import build_parser as build_parser
|
|
41
43
|
from .parser_error import (
|
pkgs/type_spec/builder.py
CHANGED
|
@@ -17,7 +17,7 @@ import regex
|
|
|
17
17
|
from pkgs.serialization import Usage
|
|
18
18
|
|
|
19
19
|
from . import util
|
|
20
|
-
from .builder_types import CrossOutputPaths
|
|
20
|
+
from .builder_types import CrossOutputPaths
|
|
21
21
|
from .non_discriminated_union_exceptions import NON_DISCRIMINATED_UNION_EXCEPTIONS
|
|
22
22
|
from .util import parse_type_str
|
|
23
23
|
|
|
@@ -83,6 +83,7 @@ class SpecProperty:
|
|
|
83
83
|
has_default: bool = False
|
|
84
84
|
# Requires this value in parsing, even if it has a default
|
|
85
85
|
parse_require: bool = False
|
|
86
|
+
sensitive: bool = False
|
|
86
87
|
desc: str | None = None
|
|
87
88
|
# Holds extra information that will be emitted along with type_info. The builder knows nothing
|
|
88
89
|
# about the contents of this information.
|
|
@@ -417,6 +418,7 @@ class SpecTypeDefn(SpecType):
|
|
|
417
418
|
"extant",
|
|
418
419
|
"label",
|
|
419
420
|
"name_case",
|
|
421
|
+
"sensitive",
|
|
420
422
|
"type",
|
|
421
423
|
],
|
|
422
424
|
)
|
|
@@ -499,6 +501,11 @@ class SpecTypeDefn(SpecType):
|
|
|
499
501
|
|
|
500
502
|
ext_info = data.get("ext_info")
|
|
501
503
|
label = data.get("label")
|
|
504
|
+
sensitive = data.get("sensitive", False)
|
|
505
|
+
builder.ensure(
|
|
506
|
+
isinstance(sensitive, bool),
|
|
507
|
+
f"sensitive must be a boolean for property {name}",
|
|
508
|
+
)
|
|
502
509
|
|
|
503
510
|
return SpecProperty(
|
|
504
511
|
name=name,
|
|
@@ -511,6 +518,7 @@ class SpecTypeDefn(SpecType):
|
|
|
511
518
|
has_default=has_default,
|
|
512
519
|
default=default,
|
|
513
520
|
parse_require=parse_require,
|
|
521
|
+
sensitive=sensitive,
|
|
514
522
|
desc=data.get("desc", None),
|
|
515
523
|
ext_info=ext_info,
|
|
516
524
|
explicit_default=explicit_default,
|
|
@@ -532,6 +540,13 @@ class SpecTypeDefn(SpecType):
|
|
|
532
540
|
return self.namespace.usage
|
|
533
541
|
|
|
534
542
|
|
|
543
|
+
@dataclass(kw_only=True, frozen=True)
|
|
544
|
+
class PythonParseFallback:
|
|
545
|
+
legacy_property: str
|
|
546
|
+
convert_namespace: SpecNamespace
|
|
547
|
+
convert: str
|
|
548
|
+
|
|
549
|
+
|
|
535
550
|
class SpecTypeGenericParameter(SpecType):
|
|
536
551
|
def __init__(
|
|
537
552
|
self,
|
|
@@ -697,13 +712,22 @@ class SpecTypeDefnObject(SpecTypeDefn):
|
|
|
697
712
|
isinstance(legacy_property, str) and isinstance(convert, str),
|
|
698
713
|
f"python_parse_fallbacks: {property_name} legacy_property and convert must be strings",
|
|
699
714
|
)
|
|
715
|
+
convert_namespace_path, _, convert_function = convert.rpartition(".")
|
|
716
|
+
convert_namespace = builder.namespaces.get(convert_namespace_path)
|
|
717
|
+
builder.ensure(
|
|
718
|
+
convert_namespace is not None,
|
|
719
|
+
f"python_parse_fallbacks: {property_name} convert must be <namespace>.<function> with a known namespace, got {convert}",
|
|
720
|
+
)
|
|
721
|
+
assert convert_namespace is not None
|
|
700
722
|
builder.ensure_python_prepart_function(
|
|
701
|
-
|
|
702
|
-
function_name=
|
|
723
|
+
namespace=convert_namespace,
|
|
724
|
+
function_name=convert_function,
|
|
703
725
|
option_name="python_parse_fallbacks",
|
|
704
726
|
)
|
|
705
727
|
parse_fallbacks[property_name] = PythonParseFallback(
|
|
706
|
-
legacy_property=legacy_property,
|
|
728
|
+
legacy_property=legacy_property,
|
|
729
|
+
convert_namespace=convert_namespace,
|
|
730
|
+
convert=convert_function,
|
|
707
731
|
)
|
|
708
732
|
return parse_fallbacks
|
|
709
733
|
|
|
@@ -1097,6 +1121,16 @@ class SpecTypeDefnStringEnum(SpecTypeDefn):
|
|
|
1097
1121
|
return self.source_enums
|
|
1098
1122
|
|
|
1099
1123
|
|
|
1124
|
+
SpecTypeDefnVariant = (
|
|
1125
|
+
SpecTypeDefnAlias
|
|
1126
|
+
| SpecTypeDefnExternal
|
|
1127
|
+
| SpecTypeDefnNewType
|
|
1128
|
+
| SpecTypeDefnObject
|
|
1129
|
+
| SpecTypeDefnStringEnum
|
|
1130
|
+
| SpecTypeDefnUnion
|
|
1131
|
+
)
|
|
1132
|
+
|
|
1133
|
+
|
|
1100
1134
|
TOKEN_ENDPOINT = "$endpoint"
|
|
1101
1135
|
TOKEN_EMIT_IO_TS = "$emit_io_ts"
|
|
1102
1136
|
TOKEN_EMIT_TYPE_INFO = "$emit_type_info"
|
|
@@ -1202,6 +1236,7 @@ def parse_endpoint_specific_path(
|
|
|
1202
1236
|
|
|
1203
1237
|
class SpecEndpoint:
|
|
1204
1238
|
method: RouteMethod
|
|
1239
|
+
alternate_methods: list[RouteMethod]
|
|
1205
1240
|
data_loader: bool
|
|
1206
1241
|
is_sdk: EndpointEmitType
|
|
1207
1242
|
stability_level: StabilityLevel | None
|
|
@@ -1230,6 +1265,7 @@ class SpecEndpoint:
|
|
|
1230
1265
|
data,
|
|
1231
1266
|
[
|
|
1232
1267
|
"method",
|
|
1268
|
+
"alternate_methods",
|
|
1233
1269
|
"path",
|
|
1234
1270
|
"data_loader",
|
|
1235
1271
|
"deprecated",
|
|
@@ -1250,6 +1286,26 @@ class SpecEndpoint:
|
|
|
1250
1286
|
)
|
|
1251
1287
|
self.method = RouteMethod(data["method"])
|
|
1252
1288
|
|
|
1289
|
+
alternate_methods_raw = data.get("alternate_methods", [])
|
|
1290
|
+
assert isinstance(alternate_methods_raw, list)
|
|
1291
|
+
self.alternate_methods = [
|
|
1292
|
+
RouteMethod(alternate_method) for alternate_method in alternate_methods_raw
|
|
1293
|
+
]
|
|
1294
|
+
assert self.method not in self.alternate_methods, (
|
|
1295
|
+
"alternate-methods-must-not-repeat-method"
|
|
1296
|
+
)
|
|
1297
|
+
assert len(set(self.alternate_methods)) == len(self.alternate_methods), (
|
|
1298
|
+
"alternate-methods-must-be-unique"
|
|
1299
|
+
)
|
|
1300
|
+
if self.alternate_methods:
|
|
1301
|
+
assert self.method == RouteMethod.get, (
|
|
1302
|
+
"alternate-methods-require-get-primary-method"
|
|
1303
|
+
)
|
|
1304
|
+
assert all(
|
|
1305
|
+
alternate_method == RouteMethod.post
|
|
1306
|
+
for alternate_method in self.alternate_methods
|
|
1307
|
+
), "alternate-methods-must-be-post"
|
|
1308
|
+
|
|
1253
1309
|
data_loader = data.get("data_loader", False)
|
|
1254
1310
|
assert isinstance(data_loader, bool)
|
|
1255
1311
|
self.data_loader = data_loader
|
|
@@ -1477,7 +1533,7 @@ class SpecNamespace:
|
|
|
1477
1533
|
self,
|
|
1478
1534
|
name: str,
|
|
1479
1535
|
):
|
|
1480
|
-
self.types: dict[str,
|
|
1536
|
+
self.types: dict[str, SpecTypeDefnVariant] = {}
|
|
1481
1537
|
self.constants: dict[str, SpecConstant] = {}
|
|
1482
1538
|
self.endpoint: SpecEndpoint | None = None
|
|
1483
1539
|
self.emit_io_ts = False
|
|
@@ -1575,7 +1631,7 @@ class SpecNamespace:
|
|
|
1575
1631
|
assert name not in self.types, f"{name} is duplicate"
|
|
1576
1632
|
defn_type = defn.get("type")
|
|
1577
1633
|
assert isinstance(defn_type, str), f"{name} requires a string type"
|
|
1578
|
-
spec_type:
|
|
1634
|
+
spec_type: SpecTypeDefnVariant
|
|
1579
1635
|
named_parameters = (
|
|
1580
1636
|
[
|
|
1581
1637
|
parameter.name
|
|
@@ -1806,13 +1862,14 @@ class SpecBuilder:
|
|
|
1806
1862
|
raise BuilderError()
|
|
1807
1863
|
|
|
1808
1864
|
def ensure_python_prepart_function(
|
|
1809
|
-
self, *,
|
|
1865
|
+
self, *, namespace: SpecNamespace, function_name: str, option_name: str
|
|
1810
1866
|
) -> None:
|
|
1811
|
-
|
|
1867
|
+
namespace_key = ".".join(namespace.path)
|
|
1868
|
+
python_prepart = self.preparts["python"].get(namespace_key, "")
|
|
1812
1869
|
def_prefix = f"def {function_name}"
|
|
1813
1870
|
self.ensure(
|
|
1814
1871
|
f"{def_prefix}(" in python_prepart or f"{def_prefix}[" in python_prepart,
|
|
1815
|
-
f"{option_name}: the {
|
|
1872
|
+
f"{option_name}: the {namespace.name} python prepart file must define {function_name}",
|
|
1816
1873
|
)
|
|
1817
1874
|
|
|
1818
1875
|
def prescan(self, namespace_path: str, data: RawDict) -> None:
|
pkgs/type_spec/builder_types.py
CHANGED
pkgs/type_spec/emit_open_api.py
CHANGED
|
@@ -4,6 +4,7 @@ Generates an OpenAPI specification based on the type_spec definitions
|
|
|
4
4
|
WORK-IN-PROGRESS, DON'T USE!
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import copy
|
|
7
8
|
import dataclasses
|
|
8
9
|
import json
|
|
9
10
|
import re
|
|
@@ -248,12 +249,12 @@ def _emit_endpoint_parameter_examples(
|
|
|
248
249
|
|
|
249
250
|
|
|
250
251
|
def _emit_endpoint_parameters(
|
|
251
|
-
|
|
252
|
+
method: str,
|
|
252
253
|
argument_type: OpenAPIType | None,
|
|
253
254
|
examples: list[EmitOpenAPIEndpointExample],
|
|
254
255
|
) -> DictApiSchema:
|
|
255
256
|
if (
|
|
256
|
-
|
|
257
|
+
method.lower() not in _QUERY_PARM_METHODS
|
|
257
258
|
or argument_type is None
|
|
258
259
|
or _is_empty_object_type(argument_type)
|
|
259
260
|
):
|
|
@@ -307,12 +308,12 @@ def _emit_stability_level(
|
|
|
307
308
|
|
|
308
309
|
|
|
309
310
|
def _emit_endpoint_request_body(
|
|
310
|
-
|
|
311
|
+
method: str,
|
|
311
312
|
arguments_type: OpenAPIType | None,
|
|
312
313
|
examples: list[EmitOpenAPIEndpointExample],
|
|
313
314
|
) -> DictApiSchema:
|
|
314
315
|
if (
|
|
315
|
-
|
|
316
|
+
method.lower() not in _REQUEST_BODY_METHODS
|
|
316
317
|
or arguments_type is None
|
|
317
318
|
or _is_empty_object_type(arguments_type)
|
|
318
319
|
):
|
|
@@ -406,6 +407,40 @@ def _emit_endpoint_description(
|
|
|
406
407
|
return {"description": full_description}
|
|
407
408
|
|
|
408
409
|
|
|
410
|
+
def _emit_endpoint_operation(
|
|
411
|
+
*,
|
|
412
|
+
endpoint: EmitOpenAPIEndpoint,
|
|
413
|
+
method: str,
|
|
414
|
+
argument_type: OpenAPIType | None,
|
|
415
|
+
) -> DictApiSchema:
|
|
416
|
+
return (
|
|
417
|
+
{
|
|
418
|
+
"tags": endpoint.tags,
|
|
419
|
+
"summary": endpoint.summary,
|
|
420
|
+
}
|
|
421
|
+
| _emit_endpoint_deprecated(endpoint.deprecated)
|
|
422
|
+
| _emit_endpoint_description(
|
|
423
|
+
endpoint.description, endpoint.guides, endpoint.stability_level
|
|
424
|
+
)
|
|
425
|
+
| _emit_stability_level(endpoint.stability_level)
|
|
426
|
+
| _emit_endpoint_parameters(method, argument_type, endpoint.examples)
|
|
427
|
+
| _emit_endpoint_request_body(method, argument_type, endpoint.examples)
|
|
428
|
+
| {
|
|
429
|
+
"responses": {
|
|
430
|
+
"200": {
|
|
431
|
+
"description": "OK",
|
|
432
|
+
"content": {
|
|
433
|
+
"application/json": {
|
|
434
|
+
"schema": {"$ref": "#/components/schema/Data"}
|
|
435
|
+
}
|
|
436
|
+
| _emit_endpoint_response_examples(endpoint.examples)
|
|
437
|
+
},
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
}
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
|
|
409
444
|
def _emit_namespace(
|
|
410
445
|
gctx: EmitOpenAPIGlobalContext,
|
|
411
446
|
ctx: EmitOpenAPIContext,
|
|
@@ -432,36 +467,14 @@ def _emit_namespace(
|
|
|
432
467
|
if ctx.endpoint is not None:
|
|
433
468
|
endpoint = ctx.endpoint
|
|
434
469
|
argument_type = ctx.types.get(ARGUMENTS_TYPE_NAME)
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
}
|
|
441
|
-
| _emit_endpoint_deprecated(endpoint.deprecated)
|
|
442
|
-
| _emit_endpoint_description(
|
|
443
|
-
endpoint.description, ctx.endpoint.guides, endpoint.stability_level
|
|
444
|
-
)
|
|
445
|
-
| _emit_stability_level(endpoint.stability_level)
|
|
446
|
-
| _emit_endpoint_parameters(endpoint, argument_type, ctx.endpoint.examples)
|
|
447
|
-
| _emit_endpoint_request_body(
|
|
448
|
-
endpoint, argument_type, ctx.endpoint.examples
|
|
470
|
+
oa_components["endpoint"] = {
|
|
471
|
+
method: copy.deepcopy(
|
|
472
|
+
_emit_endpoint_operation(
|
|
473
|
+
endpoint=endpoint, method=method, argument_type=argument_type
|
|
474
|
+
)
|
|
449
475
|
)
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
"200": {
|
|
453
|
-
"description": "OK",
|
|
454
|
-
"content": {
|
|
455
|
-
"application/json": {
|
|
456
|
-
"schema": {"$ref": "#/components/schema/Data"}
|
|
457
|
-
}
|
|
458
|
-
| _emit_endpoint_response_examples(ctx.endpoint.examples)
|
|
459
|
-
},
|
|
460
|
-
}
|
|
461
|
-
},
|
|
462
|
-
}
|
|
463
|
-
)
|
|
464
|
-
oa_components["endpoint"] = oa_endpoint
|
|
476
|
+
for method in [endpoint.method, *endpoint.alternate_methods]
|
|
477
|
+
}
|
|
465
478
|
|
|
466
479
|
types = ctx.types
|
|
467
480
|
if ctx.endpoint is not None:
|
|
@@ -682,6 +695,10 @@ def _emit_endpoint(
|
|
|
682
695
|
|
|
683
696
|
ctx.endpoint = EmitOpenAPIEndpoint(
|
|
684
697
|
method=namespace.endpoint.method.lower(),
|
|
698
|
+
alternate_methods=[
|
|
699
|
+
alternate_method.lower()
|
|
700
|
+
for alternate_method in namespace.endpoint.alternate_methods
|
|
701
|
+
],
|
|
685
702
|
tags=[tag_name],
|
|
686
703
|
summary=f"{'/'.join(namespace.path[path_cutoff:])}",
|
|
687
704
|
description=description,
|