UncountablePythonSDK 0.0.176__py3-none-any.whl → 0.0.177__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.
- docs/conf.py +20 -0
- uncountable/core/file_upload.py +18 -13
- uncountable/core/query/builder.py +10 -1
- uncountable/core/query/column.py +29 -0
- uncountable/types/entity_t.py +2 -0
- {uncountablepythonsdk-0.0.176.dist-info → uncountablepythonsdk-0.0.177.dist-info}/METADATA +1 -1
- {uncountablepythonsdk-0.0.176.dist-info → uncountablepythonsdk-0.0.177.dist-info}/RECORD +9 -9
- {uncountablepythonsdk-0.0.176.dist-info → uncountablepythonsdk-0.0.177.dist-info}/WHEEL +0 -0
- {uncountablepythonsdk-0.0.176.dist-info → uncountablepythonsdk-0.0.177.dist-info}/top_level.txt +0 -0
docs/conf.py
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
|
8
8
|
|
|
9
9
|
import datetime
|
|
10
|
+
import importlib
|
|
11
|
+
import inspect
|
|
10
12
|
|
|
11
13
|
from docutils import nodes # type: ignore[import-untyped]
|
|
12
14
|
from sphinx.addnodes import pending_xref # type: ignore[import-not-found]
|
|
@@ -63,6 +65,20 @@ favicons = [
|
|
|
63
65
|
]
|
|
64
66
|
|
|
65
67
|
|
|
68
|
+
def _resolve_alias_to_real_module(target_module: str) -> str:
|
|
69
|
+
if "." not in target_module:
|
|
70
|
+
return target_module
|
|
71
|
+
parent_name, attr_name = target_module.rsplit(".", 1)
|
|
72
|
+
try:
|
|
73
|
+
parent = importlib.import_module(parent_name)
|
|
74
|
+
except ImportError:
|
|
75
|
+
return target_module
|
|
76
|
+
aliased = getattr(parent, attr_name, None)
|
|
77
|
+
if not inspect.ismodule(aliased) or aliased.__name__ == target_module:
|
|
78
|
+
return target_module
|
|
79
|
+
return aliased.__name__
|
|
80
|
+
|
|
81
|
+
|
|
66
82
|
def _hook_missing_reference(
|
|
67
83
|
_app: Sphinx, _env: BuildEnvironment, node: pending_xref, contnode: nodes.Text
|
|
68
84
|
) -> nodes.reference | None:
|
|
@@ -80,6 +96,10 @@ def _hook_missing_reference(
|
|
|
80
96
|
return None
|
|
81
97
|
|
|
82
98
|
target_module, target_name = target.rsplit(".", 1)
|
|
99
|
+
real_module = _resolve_alias_to_real_module(target_module)
|
|
100
|
+
if real_module != target_module:
|
|
101
|
+
target_module = real_module
|
|
102
|
+
target = f"{target_module}.{target_name}"
|
|
83
103
|
|
|
84
104
|
# construct relative path from current doc page to target page
|
|
85
105
|
relative_segments_to_root = [".." for _ in current_doc.split("/")]
|
uncountable/core/file_upload.py
CHANGED
|
@@ -17,6 +17,7 @@ from uncountable.types import uploader_t
|
|
|
17
17
|
from .types import AuthDetailsAll, AuthDetailsApiKey
|
|
18
18
|
|
|
19
19
|
_CHUNK_SIZE = 5 * 1024 * 1024 # s3 requires 5MiB minimum
|
|
20
|
+
_PARSED_FILE_DATA_FILENAME = "parsed_file_data.json"
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class FileUploadType(StrEnum):
|
|
@@ -51,17 +52,27 @@ class UploaderFileUpload:
|
|
|
51
52
|
FileUpload = MediaFileUpload | DataFileUpload | UploaderFileUpload
|
|
52
53
|
|
|
53
54
|
|
|
54
|
-
@dataclass(kw_only=True)
|
|
55
|
-
class _ParsedFileDataWrapper:
|
|
56
|
-
parsed_file_data: list[uploader_t.ParsedFileData]
|
|
57
|
-
|
|
58
|
-
|
|
59
55
|
@dataclass(kw_only=True)
|
|
60
56
|
class FileBytes:
|
|
61
57
|
name: str
|
|
62
58
|
bytes_data: BytesIO
|
|
63
59
|
|
|
64
60
|
|
|
61
|
+
def _build_parsed_file_data_bytes(
|
|
62
|
+
*, parsed_file_data: list[uploader_t.ParsedFileData]
|
|
63
|
+
) -> FileBytes:
|
|
64
|
+
buffer = BytesIO()
|
|
65
|
+
buffer.write(b'{"parsed_file_data": [')
|
|
66
|
+
for index, file_data in enumerate(parsed_file_data):
|
|
67
|
+
if index > 0:
|
|
68
|
+
buffer.write(b", ")
|
|
69
|
+
serialized_file_data = serialize_for_storage(file_data)
|
|
70
|
+
buffer.write(json.dumps(serialized_file_data).encode("utf-8"))
|
|
71
|
+
buffer.write(b"]}")
|
|
72
|
+
buffer.seek(0)
|
|
73
|
+
return FileBytes(name=_PARSED_FILE_DATA_FILENAME, bytes_data=buffer)
|
|
74
|
+
|
|
75
|
+
|
|
65
76
|
@contextmanager
|
|
66
77
|
def file_upload_data(file_upload: FileUpload) -> Generator[FileBytes, None, None]:
|
|
67
78
|
match file_upload:
|
|
@@ -73,15 +84,9 @@ def file_upload_data(file_upload: FileUpload) -> Generator[FileBytes, None, None
|
|
|
73
84
|
case DataFileUpload():
|
|
74
85
|
yield FileBytes(name=file_upload.name, bytes_data=file_upload.data)
|
|
75
86
|
case UploaderFileUpload():
|
|
76
|
-
|
|
87
|
+
yield _build_parsed_file_data_bytes(
|
|
77
88
|
parsed_file_data=file_upload.parsed_file_data
|
|
78
89
|
)
|
|
79
|
-
serialized = serialize_for_storage(wrapper)
|
|
80
|
-
json_bytes = json.dumps(serialized).encode("utf-8")
|
|
81
|
-
yield FileBytes(
|
|
82
|
-
name="parsed_file_data.json",
|
|
83
|
-
bytes_data=BytesIO(json_bytes),
|
|
84
|
-
)
|
|
85
90
|
|
|
86
91
|
|
|
87
92
|
@dataclass(kw_only=True)
|
|
@@ -135,7 +140,7 @@ class FileUploader:
|
|
|
135
140
|
case DataFileUpload():
|
|
136
141
|
attributes["file_name"] = file_upload.name
|
|
137
142
|
case UploaderFileUpload():
|
|
138
|
-
attributes["file_name"] =
|
|
143
|
+
attributes["file_name"] = _PARSED_FILE_DATA_FILENAME
|
|
139
144
|
case _:
|
|
140
145
|
assert_never(file_upload)
|
|
141
146
|
with push_scope_optional(
|
|
@@ -13,6 +13,7 @@ from uncountable.core.query.column import (
|
|
|
13
13
|
Column,
|
|
14
14
|
ColumnFilter,
|
|
15
15
|
EnumColumn,
|
|
16
|
+
JsonColumn,
|
|
16
17
|
NullableColumn,
|
|
17
18
|
PrimaryKeyColumn,
|
|
18
19
|
get_column_base,
|
|
@@ -72,8 +73,16 @@ class QueryBuilder[QueryRowT: QueryRow]:
|
|
|
72
73
|
column.identifier for column in column_definitions.values()
|
|
73
74
|
)
|
|
74
75
|
self._property_names: tuple[str, ...] = tuple(column_definitions.keys())
|
|
76
|
+
json_property_names = {
|
|
77
|
+
name
|
|
78
|
+
for name, column in column_definitions.items()
|
|
79
|
+
if isinstance(column, JsonColumn)
|
|
80
|
+
}
|
|
75
81
|
self._parser: CachedParser = CachedParser(
|
|
76
|
-
serial_class(
|
|
82
|
+
serial_class(
|
|
83
|
+
unconverted_keys={*self._property_names},
|
|
84
|
+
unconverted_values=json_property_names,
|
|
85
|
+
)(
|
|
77
86
|
make_dataclass(
|
|
78
87
|
cls_name=self._model.__name__,
|
|
79
88
|
fields=[
|
uncountable/core/query/column.py
CHANGED
|
@@ -465,6 +465,27 @@ class NullableTextsColumn[
|
|
|
465
465
|
# IMPROVE: Implement "Not Exists" filter (when supported in SDK)
|
|
466
466
|
|
|
467
467
|
|
|
468
|
+
class JsonColumn(Column[base_t.JsonValue, NullableColumn]):
|
|
469
|
+
__hash__ = Column.__hash__
|
|
470
|
+
|
|
471
|
+
def __init__(self, identifier: listing_t.ColumnIdentifier) -> None:
|
|
472
|
+
super().__init__(
|
|
473
|
+
identifier=identifier,
|
|
474
|
+
nullable=NullableColumn,
|
|
475
|
+
value_type=(
|
|
476
|
+
dict[str, base_t.JsonValue] | list[base_t.JsonValue] | base_t.JsonScalar
|
|
477
|
+
),
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
def __ne__(self, other: None) -> ColumnFilter: # type: ignore[override]
|
|
481
|
+
return ColumnFilter(
|
|
482
|
+
identifier=self.identifier,
|
|
483
|
+
filter=lambda identifier: listing_t.FilterSpecExists(column=identifier),
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
# IMPROVE: Implement "Not Exists" filter (when supported in SDK)
|
|
487
|
+
|
|
488
|
+
|
|
468
489
|
class PrimaryKeyColumn(
|
|
469
490
|
Column[base_t.ObjectId, NonNullableColumn],
|
|
470
491
|
):
|
|
@@ -684,6 +705,10 @@ class IdColumn[
|
|
|
684
705
|
column: NullableTextsColumn[BaseNullableT],
|
|
685
706
|
) -> NullableTextsColumn[BaseNullableT]: ...
|
|
686
707
|
|
|
708
|
+
# Json
|
|
709
|
+
@overload
|
|
710
|
+
def __rshift__(self, column: JsonColumn) -> JsonColumn: ...
|
|
711
|
+
|
|
687
712
|
# Ids
|
|
688
713
|
@overload
|
|
689
714
|
def __rshift__[
|
|
@@ -734,6 +759,7 @@ class IdColumn[
|
|
|
734
759
|
| NumericColumn[BaseNullableT]
|
|
735
760
|
| TextsColumn[BaseNullableT]
|
|
736
761
|
| NullableTextsColumn[BaseNullableT]
|
|
762
|
+
| JsonColumn
|
|
737
763
|
| IdsColumn[BaseNullableT]
|
|
738
764
|
| IdColumn[BaseNullableT],
|
|
739
765
|
) -> (
|
|
@@ -768,6 +794,7 @@ class IdColumn[
|
|
|
768
794
|
| NullableTextsColumn[BaseNullableT]
|
|
769
795
|
| NullableTextsColumn[NonNullableColumn | NullableColumn]
|
|
770
796
|
| NullableTextsColumn[NullableColumn]
|
|
797
|
+
| JsonColumn
|
|
771
798
|
| IdsColumn[BaseNullableT]
|
|
772
799
|
| IdsColumn[NonNullableColumn | NullableColumn]
|
|
773
800
|
| IdsColumn[NullableColumn]
|
|
@@ -869,6 +896,8 @@ class IdColumn[
|
|
|
869
896
|
if self.nullable is NonNullableColumn
|
|
870
897
|
else NullableColumn,
|
|
871
898
|
)
|
|
899
|
+
case JsonColumn():
|
|
900
|
+
return JsonColumn(identifier=transitive_identifier)
|
|
872
901
|
case IdsColumn():
|
|
873
902
|
return IdsColumn(
|
|
874
903
|
id_type=column.id_type,
|
uncountable/types/entity_t.py
CHANGED
|
@@ -48,6 +48,7 @@ __all__: list[str] = [
|
|
|
48
48
|
"condition_parameter_matches": "Condition Parameter Matches",
|
|
49
49
|
"condition_parameter_rule": "Condition Parameter Rule",
|
|
50
50
|
"condition_parameter_value": "Condition Parameter Value",
|
|
51
|
+
"config_transfer_export": "Config Transfer Export",
|
|
51
52
|
"constraint": "Constraint",
|
|
52
53
|
"constraint_set": "Constraint Set",
|
|
53
54
|
"control_type": "Control Type",
|
|
@@ -299,6 +300,7 @@ class EntityType(StrEnum):
|
|
|
299
300
|
CONDITION_PARAMETER_MATCHES = "condition_parameter_matches"
|
|
300
301
|
CONDITION_PARAMETER_RULE = "condition_parameter_rule"
|
|
301
302
|
CONDITION_PARAMETER_VALUE = "condition_parameter_value"
|
|
303
|
+
CONFIG_TRANSFER_EXPORT = "config_transfer_export"
|
|
302
304
|
CONSTRAINT = "constraint"
|
|
303
305
|
CONSTRAINT_SET = "constraint_set"
|
|
304
306
|
CONTROL_TYPE = "control_type"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: UncountablePythonSDK
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.177
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
docs/.flowmarkignore,sha256=gmJziQDpI3zbfHFgM73BE9iaLn04Oqya_7QCjJ749o8,548
|
|
2
2
|
docs/.gitignore,sha256=_ebkZUcwfvfnGEJ95rfj1lxoBNd6EE9ZvtOc7FsbfFE,7
|
|
3
|
-
docs/conf.py,sha256=
|
|
3
|
+
docs/conf.py,sha256=KivJNvQWboXqJ07NMgcYY5tsV6CoIfyTpZh8jdn_5Qk,4239
|
|
4
4
|
docs/index.md,sha256=g4Yi5831fEkywYkkcFohYLkKzSI91SOZF7DxKsm9zgI,3193
|
|
5
5
|
docs/justfile,sha256=WymCEQ6W2A8Ak79iUPmecmuaUNN2htb7STUrz5K7ELE,273
|
|
6
6
|
docs/requirements.txt,sha256=8aqtVaNV4AlzUZ7nAM8kxOF1ccAcujhQ_ayU9Whksf8,172
|
|
@@ -120,11 +120,11 @@ uncountable/core/__init__.py,sha256=RFv0kO6rKFf1PtBPu83hCGmxqkJamRtsgQ9_-ztw7tA,
|
|
|
120
120
|
uncountable/core/async_batch.py,sha256=9pYGFzVCQXt8059qFHgutweGIFPquJ5Xfq6NT5P-1K0,1206
|
|
121
121
|
uncountable/core/client.py,sha256=XSAPfcSU51d3MgAZOuT6FMrdrM452KQfWzNHjLOGSMY,16549
|
|
122
122
|
uncountable/core/environment.py,sha256=Z9vu7JtnSDgQB_KKcZnjTFNyARXjRr_PDW9krwxNNAo,1132
|
|
123
|
-
uncountable/core/file_upload.py,sha256=
|
|
123
|
+
uncountable/core/file_upload.py,sha256=IisvIBdm2f4CJTRQ9Awi5JuI16PSERjXrzZgmrUiCHY,5960
|
|
124
124
|
uncountable/core/types.py,sha256=s2CjqYJpsmbC7xMwxxT7kJ_V9bwokrjjWVVjpMcQpKI,333
|
|
125
125
|
uncountable/core/query/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
126
|
-
uncountable/core/query/builder.py,sha256=
|
|
127
|
-
uncountable/core/query/column.py,sha256=
|
|
126
|
+
uncountable/core/query/builder.py,sha256=LmPHfi0wdNGVn1hdYxTAU1MTsIDlVc_lgWBZFVVmZR8,8510
|
|
127
|
+
uncountable/core/query/column.py,sha256=q5Yy41oS8MNrNaHAZVoftooJExPymm2tmCTF-BAPsoY,45231
|
|
128
128
|
uncountable/core/query/row.py,sha256=dy68YKvMz336nyOsj_g2oNTLKBuUnKRUz5n99sApfT0,1600
|
|
129
129
|
uncountable/core/query/types.py,sha256=xZgc0_O1PIxZoJWQhxkg3qnSvHj3yt-bv9QX1UCOFGw,481
|
|
130
130
|
uncountable/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -196,7 +196,7 @@ uncountable/types/curves_t.py,sha256=WIML06C67yC4KWdPJR2HV_Ac7eBFTDRDUL3YgeXbFOs
|
|
|
196
196
|
uncountable/types/data.py,sha256=u2isf4XEug3Eu-xSIoqGaCQmW2dFaKBHCkP_WKYwwBc,500
|
|
197
197
|
uncountable/types/data_t.py,sha256=U_dIh5GcyaJlkrHEI4Qf4TOo1uJX07PYO70sYzzKtTo,2615
|
|
198
198
|
uncountable/types/entity.py,sha256=Zclk1LYcRaYrMDhqyCjMSLEg0fE6_q8LHvV22Qvscgs,566
|
|
199
|
-
uncountable/types/entity_t.py,sha256=
|
|
199
|
+
uncountable/types/entity_t.py,sha256=fVDQyZvpBHp6llk05entEf2ODOVcCsEGlkE1IyDfY2o,27676
|
|
200
200
|
uncountable/types/experiment_groups.py,sha256=qUpFOx1AKgzaT_4khCOv5Xs6jwiQGbvHH-GUh3v1nv4,288
|
|
201
201
|
uncountable/types/experiment_groups_t.py,sha256=QjZBdjnbsD1D-VpPSSV6hBg-Q7mujjKvYtdMewtXNVU,712
|
|
202
202
|
uncountable/types/exports.py,sha256=VMmxUO2PpV1Y63hZ2AnVor4H-B6aswJ7YpSru_u89lU,334
|
|
@@ -414,7 +414,7 @@ uncountable/types/api/uploader/complete_async_parse.py,sha256=Os1HAubxTlbut6Gylj
|
|
|
414
414
|
uncountable/types/api/uploader/invoke_uploader.py,sha256=QU1KmAFgGHSWskZEKfaAww8rCj-hVNP0i4kMQE3x3Fc,1822
|
|
415
415
|
uncountable/types/api/user/__init__.py,sha256=gCgbynxG3jA8FQHzercKtrHKHkiIKr8APdZYUniAor8,55
|
|
416
416
|
uncountable/types/api/user/get_current_user_info.py,sha256=BT7bGp5SOHz3XdKWhhdZ6acnInafT2PgdJ-H4YH3W7c,1181
|
|
417
|
-
uncountablepythonsdk-0.0.
|
|
418
|
-
uncountablepythonsdk-0.0.
|
|
419
|
-
uncountablepythonsdk-0.0.
|
|
420
|
-
uncountablepythonsdk-0.0.
|
|
417
|
+
uncountablepythonsdk-0.0.177.dist-info/METADATA,sha256=gvqE0J2wNYcjjbTIjMPWR8fF1tB5p0Z2DCG0Z4-tiFc,2175
|
|
418
|
+
uncountablepythonsdk-0.0.177.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
419
|
+
uncountablepythonsdk-0.0.177.dist-info/top_level.txt,sha256=1UVGjAU-6hJY9qw2iJ7nCBeEwZ793AEN5ZfKX9A1uj4,31
|
|
420
|
+
uncountablepythonsdk-0.0.177.dist-info/RECORD,,
|
|
File without changes
|
{uncountablepythonsdk-0.0.176.dist-info → uncountablepythonsdk-0.0.177.dist-info}/top_level.txt
RENAMED
|
File without changes
|