nextmv 0.28.2__tar.gz → 0.28.3.dev0__tar.gz
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.
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/PKG-INFO +1 -1
- nextmv-0.28.3.dev0/nextmv/__about__.py +1 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/application.py +3 -2
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/client.py +9 -4
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/run.py +3 -3
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/input.py +2 -1
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/output.py +10 -52
- nextmv-0.28.3.dev0/nextmv/serialization.py +67 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/test_output.py +1 -9
- nextmv-0.28.3.dev0/tests/test_serialization.py +53 -0
- nextmv-0.28.2/nextmv/__about__.py +0 -1
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/.gitignore +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/LICENSE +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/README.md +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/__entrypoint__.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/__init__.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/base_model.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/__init__.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/acceptance_test.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/account.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/batch_experiment.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/input_set.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/instance.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/manifest.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/package.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/safe.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/scenario.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/secrets.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/status.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/cloud/version.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/deprecated.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/logger.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/model.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/nextmv/options.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/pyproject.toml +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/requirements.txt +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/__init__.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/cloud/__init__.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/cloud/app.yaml +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/cloud/test_application.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/cloud/test_client.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/cloud/test_manifest.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/cloud/test_package.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/cloud/test_run.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/cloud/test_safe_name_id.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/cloud/test_scenario.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/scripts/__init__.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/scripts/options1.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/scripts/options2.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/scripts/options3.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/scripts/options4.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/scripts/options5.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/scripts/options6.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/scripts/options7.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/scripts/options_deprecated.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/test_base_model.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/test_entrypoint/__init__.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/test_entrypoint/test_entrypoint.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/test_input.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/test_logger.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/test_model.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/test_options.py +0 -0
- {nextmv-0.28.2 → nextmv-0.28.3.dev0}/tests/test_version.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "v0.28.3.dev0"
|
|
@@ -66,6 +66,7 @@ from nextmv.logger import log
|
|
|
66
66
|
from nextmv.model import Model, ModelConfiguration
|
|
67
67
|
from nextmv.options import Options
|
|
68
68
|
from nextmv.output import Output
|
|
69
|
+
from nextmv.serialization import serialize_json
|
|
69
70
|
|
|
70
71
|
# Maximum size of the run input/output in bytes. This constant defines the
|
|
71
72
|
# maximum allowed size for run inputs and outputs. When the size exceeds this
|
|
@@ -1588,7 +1589,7 @@ class Application:
|
|
|
1588
1589
|
if isinstance(v, str):
|
|
1589
1590
|
options_dict[k] = v
|
|
1590
1591
|
else:
|
|
1591
|
-
options_dict[k] =
|
|
1592
|
+
options_dict[k] = serialize_json(v)
|
|
1592
1593
|
|
|
1593
1594
|
payload = {}
|
|
1594
1595
|
if upload_id_used:
|
|
@@ -2830,7 +2831,7 @@ class Application:
|
|
|
2830
2831
|
"""
|
|
2831
2832
|
|
|
2832
2833
|
if isinstance(input, dict):
|
|
2833
|
-
input =
|
|
2834
|
+
input = serialize_json(input)
|
|
2834
2835
|
|
|
2835
2836
|
self.client.upload_to_presigned_url(
|
|
2836
2837
|
url=upload_url.upload_url,
|
|
@@ -14,7 +14,6 @@ get_size(obj)
|
|
|
14
14
|
Finds the size of an object in bytes.
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
import json
|
|
18
17
|
import os
|
|
19
18
|
from dataclasses import dataclass, field
|
|
20
19
|
from typing import IO, Any, Optional, Union
|
|
@@ -24,6 +23,8 @@ import requests
|
|
|
24
23
|
import yaml
|
|
25
24
|
from requests.adapters import HTTPAdapter, Retry
|
|
26
25
|
|
|
26
|
+
from nextmv.serialization import serialize_json
|
|
27
|
+
|
|
27
28
|
_MAX_LAMBDA_PAYLOAD_SIZE: int = 500 * 1024 * 1024
|
|
28
29
|
"""int: Maximum size of the payload handled by the Nextmv Cloud API.
|
|
29
30
|
|
|
@@ -293,7 +294,11 @@ class Client:
|
|
|
293
294
|
if data is not None:
|
|
294
295
|
kwargs["data"] = data
|
|
295
296
|
if payload is not None:
|
|
296
|
-
|
|
297
|
+
if isinstance(payload, (dict, list)):
|
|
298
|
+
data = serialize_json(payload)
|
|
299
|
+
kwargs["data"] = data
|
|
300
|
+
else:
|
|
301
|
+
raise ValueError("payload must be a dictionary or a list")
|
|
297
302
|
if query_params is not None:
|
|
298
303
|
kwargs["params"] = query_params
|
|
299
304
|
|
|
@@ -341,7 +346,7 @@ class Client:
|
|
|
341
346
|
|
|
342
347
|
upload_data: Optional[str] = None
|
|
343
348
|
if isinstance(data, dict):
|
|
344
|
-
upload_data =
|
|
349
|
+
upload_data = serialize_json(data)
|
|
345
350
|
elif isinstance(data, str):
|
|
346
351
|
upload_data = data
|
|
347
352
|
else:
|
|
@@ -436,7 +441,7 @@ def get_size(obj: Union[dict[str, Any], IO[bytes], str]) -> int:
|
|
|
436
441
|
"""
|
|
437
442
|
|
|
438
443
|
if isinstance(obj, dict):
|
|
439
|
-
obj_str =
|
|
444
|
+
obj_str = serialize_json(obj)
|
|
440
445
|
return len(obj_str.encode("utf-8"))
|
|
441
446
|
|
|
442
447
|
elif hasattr(obj, "read"):
|
|
@@ -39,7 +39,6 @@ run_duration(start, end)
|
|
|
39
39
|
Calculate the duration of a run in milliseconds.
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
-
import json
|
|
43
42
|
from dataclasses import dataclass
|
|
44
43
|
from datetime import datetime
|
|
45
44
|
from enum import Enum
|
|
@@ -51,6 +50,7 @@ from nextmv.base_model import BaseModel
|
|
|
51
50
|
from nextmv.cloud.status import Status, StatusV2
|
|
52
51
|
from nextmv.input import Input, InputFormat
|
|
53
52
|
from nextmv.output import Output, OutputFormat
|
|
53
|
+
from nextmv.serialization import serialize_json
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
def run_duration(start: Union[datetime, float], end: Union[datetime, float]) -> int:
|
|
@@ -628,7 +628,7 @@ class TrackedRun:
|
|
|
628
628
|
raise ValueError("Input.input_format must be JSON.")
|
|
629
629
|
elif isinstance(self.input, dict):
|
|
630
630
|
try:
|
|
631
|
-
_ =
|
|
631
|
+
_ = serialize_json(self.input)
|
|
632
632
|
except (TypeError, OverflowError) as e:
|
|
633
633
|
raise ValueError("Input is dict[str, Any] but it is not JSON serializable") from e
|
|
634
634
|
|
|
@@ -637,7 +637,7 @@ class TrackedRun:
|
|
|
637
637
|
raise ValueError("Output.output_format must be JSON.")
|
|
638
638
|
elif isinstance(self.output, dict):
|
|
639
639
|
try:
|
|
640
|
-
_ =
|
|
640
|
+
_ = serialize_json(self.output)
|
|
641
641
|
except (TypeError, OverflowError) as e:
|
|
642
642
|
raise ValueError("Output is dict[str, Any] but it is not JSON serializable") from e
|
|
643
643
|
|
|
@@ -33,6 +33,7 @@ from typing import Any, Optional, Union
|
|
|
33
33
|
|
|
34
34
|
from nextmv.deprecated import deprecated
|
|
35
35
|
from nextmv.options import Options
|
|
36
|
+
from nextmv.serialization import serialize_json
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
class InputFormat(str, Enum):
|
|
@@ -139,7 +140,7 @@ class Input:
|
|
|
139
140
|
|
|
140
141
|
if self.input_format == InputFormat.JSON:
|
|
141
142
|
try:
|
|
142
|
-
_ =
|
|
143
|
+
_ = serialize_json(self.data)
|
|
143
144
|
except (TypeError, OverflowError) as e:
|
|
144
145
|
raise ValueError(
|
|
145
146
|
f"Input has input_format InputFormat.JSON and "
|
|
@@ -42,8 +42,6 @@ write
|
|
|
42
42
|
|
|
43
43
|
import copy
|
|
44
44
|
import csv
|
|
45
|
-
import datetime
|
|
46
|
-
import json
|
|
47
45
|
import os
|
|
48
46
|
import sys
|
|
49
47
|
from dataclasses import dataclass
|
|
@@ -56,6 +54,7 @@ from nextmv.base_model import BaseModel
|
|
|
56
54
|
from nextmv.deprecated import deprecated
|
|
57
55
|
from nextmv.logger import reset_stdout
|
|
58
56
|
from nextmv.options import Options
|
|
57
|
+
from nextmv.serialization import serialize_json
|
|
59
58
|
|
|
60
59
|
|
|
61
60
|
class RunStatistics(BaseModel):
|
|
@@ -644,7 +643,7 @@ class Output:
|
|
|
644
643
|
|
|
645
644
|
if self.output_format == OutputFormat.JSON:
|
|
646
645
|
try:
|
|
647
|
-
_ =
|
|
646
|
+
_ = serialize_json(self.solution)
|
|
648
647
|
except (TypeError, OverflowError) as e:
|
|
649
648
|
raise ValueError(
|
|
650
649
|
f"Output has output_format OutputFormat.JSON and "
|
|
@@ -722,12 +721,6 @@ class Output:
|
|
|
722
721
|
and self.csv_configurations != {}
|
|
723
722
|
):
|
|
724
723
|
output_dict["csv_configurations"] = self.csv_configurations
|
|
725
|
-
elif (
|
|
726
|
-
self.output_format == OutputFormat.JSON
|
|
727
|
-
and self.json_configurations is not None
|
|
728
|
-
and self.json_configurations != {}
|
|
729
|
-
):
|
|
730
|
-
output_dict["json_configurations"] = self.json_configurations
|
|
731
724
|
|
|
732
725
|
return output_dict
|
|
733
726
|
|
|
@@ -822,19 +815,9 @@ class LocalOutputWriter(OutputWriter):
|
|
|
822
815
|
if hasattr(output, "json_configurations") and output.json_configurations is not None:
|
|
823
816
|
json_configurations = output.json_configurations
|
|
824
817
|
|
|
825
|
-
|
|
826
|
-
if "indent" in json_configurations:
|
|
827
|
-
indent = json_configurations["indent"]
|
|
828
|
-
del json_configurations["indent"]
|
|
829
|
-
if "default" in json_configurations:
|
|
830
|
-
custom_serial = json_configurations["default"]
|
|
831
|
-
del json_configurations["default"]
|
|
832
|
-
|
|
833
|
-
serialized = json.dumps(
|
|
818
|
+
serialized = serialize_json(
|
|
834
819
|
output_dict,
|
|
835
|
-
|
|
836
|
-
default=custom_serial,
|
|
837
|
-
**json_configurations,
|
|
820
|
+
json_configurations=json_configurations,
|
|
838
821
|
)
|
|
839
822
|
|
|
840
823
|
if path is None or path == "":
|
|
@@ -877,13 +860,17 @@ class LocalOutputWriter(OutputWriter):
|
|
|
877
860
|
if not os.path.exists(dir_path):
|
|
878
861
|
os.makedirs(dir_path)
|
|
879
862
|
|
|
880
|
-
|
|
863
|
+
json_configurations = {}
|
|
864
|
+
if hasattr(output, "json_configurations") and output.json_configurations is not None:
|
|
865
|
+
json_configurations = output.json_configurations
|
|
866
|
+
|
|
867
|
+
serialized = serialize_json(
|
|
881
868
|
{
|
|
882
869
|
"options": output_dict.get("options", {}),
|
|
883
870
|
"statistics": output_dict.get("statistics", {}),
|
|
884
871
|
"assets": output_dict.get("assets", []),
|
|
885
872
|
},
|
|
886
|
-
|
|
873
|
+
json_configurations=json_configurations,
|
|
887
874
|
)
|
|
888
875
|
print(serialized, file=sys.stdout)
|
|
889
876
|
|
|
@@ -1118,32 +1105,3 @@ def write(
|
|
|
1118
1105
|
"""
|
|
1119
1106
|
|
|
1120
1107
|
writer.write(output, path, skip_stdout_reset)
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
def _custom_serial(obj: Any) -> str:
|
|
1124
|
-
"""
|
|
1125
|
-
JSON serializer for objects not serializable by default json serializer.
|
|
1126
|
-
|
|
1127
|
-
This function provides custom serialization for datetime objects, converting
|
|
1128
|
-
them to ISO format strings.
|
|
1129
|
-
|
|
1130
|
-
Parameters
|
|
1131
|
-
----------
|
|
1132
|
-
obj : Any
|
|
1133
|
-
The object to serialize.
|
|
1134
|
-
|
|
1135
|
-
Returns
|
|
1136
|
-
-------
|
|
1137
|
-
str
|
|
1138
|
-
The serialized representation of the object.
|
|
1139
|
-
|
|
1140
|
-
Raises
|
|
1141
|
-
------
|
|
1142
|
-
TypeError
|
|
1143
|
-
If the object type is not supported for serialization.
|
|
1144
|
-
"""
|
|
1145
|
-
|
|
1146
|
-
if isinstance(obj, (datetime.datetime | datetime.date)):
|
|
1147
|
-
return obj.isoformat()
|
|
1148
|
-
|
|
1149
|
-
raise TypeError(f"Type {type(obj)} not serializable")
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import json
|
|
3
|
+
from typing import Any, Union
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def serialize_json(
|
|
7
|
+
obj: Union[dict, list],
|
|
8
|
+
json_configurations: dict[str, Any] = None,
|
|
9
|
+
) -> str:
|
|
10
|
+
"""
|
|
11
|
+
Serialize a Python object (dict or list) to a JSON string.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
obj : Union[dict, list]
|
|
16
|
+
The Python object to serialize.
|
|
17
|
+
json_configurations : dict, optional
|
|
18
|
+
Additional configurations for JSON serialization. This allows customization
|
|
19
|
+
of the Python `json.dumps` function. You can specify parameters like `indent`
|
|
20
|
+
for pretty printing or `default` for custom serialization functions.
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
str
|
|
25
|
+
A JSON string representation of the object.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
# Apply some default configuration if not provided
|
|
29
|
+
json_configurations = json_configurations or {}
|
|
30
|
+
if "default" not in json_configurations:
|
|
31
|
+
json_configurations["default"] = _custom_serial
|
|
32
|
+
if "separators" not in json_configurations:
|
|
33
|
+
json_configurations["separators"] = (",", ":")
|
|
34
|
+
|
|
35
|
+
return json.dumps(
|
|
36
|
+
obj,
|
|
37
|
+
**json_configurations,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _custom_serial(obj: Any) -> str:
|
|
42
|
+
"""
|
|
43
|
+
JSON serializer for objects not serializable by default json serializer.
|
|
44
|
+
|
|
45
|
+
This function provides custom serialization for datetime objects, converting
|
|
46
|
+
them to ISO format strings.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
obj : Any
|
|
51
|
+
The object to serialize.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
str
|
|
56
|
+
The serialized representation of the object.
|
|
57
|
+
|
|
58
|
+
Raises
|
|
59
|
+
------
|
|
60
|
+
TypeError
|
|
61
|
+
If the object type is not supported for serialization.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
if isinstance(obj, (datetime.datetime, datetime.date)):
|
|
65
|
+
return obj.isoformat()
|
|
66
|
+
|
|
67
|
+
raise TypeError(f"Type {type(obj)} not serializable")
|
|
@@ -118,13 +118,6 @@ class TestOutput(unittest.TestCase):
|
|
|
118
118
|
result = output.to_dict()
|
|
119
119
|
self.assertEqual(result["assets"][0]["name"], "asset3")
|
|
120
120
|
|
|
121
|
-
# Test with JSON configurations
|
|
122
|
-
json_config = {"indent": 4, "sort_keys": True}
|
|
123
|
-
output = nextmv.Output(output_format=nextmv.OutputFormat.JSON, json_configurations=json_config)
|
|
124
|
-
result = output.to_dict()
|
|
125
|
-
self.assertEqual(result["json_configurations"]["indent"], 4)
|
|
126
|
-
self.assertEqual(result["json_configurations"]["sort_keys"], True)
|
|
127
|
-
|
|
128
121
|
# Test with CSV configurations
|
|
129
122
|
csv_config = {"delimiter": ";", "quoting": csv.QUOTE_NONNUMERIC}
|
|
130
123
|
output = nextmv.Output(output_format=nextmv.OutputFormat.CSV_ARCHIVE, csv_configurations=csv_config)
|
|
@@ -183,7 +176,6 @@ class TestOutput(unittest.TestCase):
|
|
|
183
176
|
self.assertEqual(result["assets"][0]["name"], "asset1")
|
|
184
177
|
self.assertEqual(result["assets"][0]["visual"]["schema"], "chartjs")
|
|
185
178
|
self.assertEqual(result["solution"]["value"], 42)
|
|
186
|
-
self.assertEqual(result["json_configurations"]["indent"], 4)
|
|
187
179
|
|
|
188
180
|
def test_local_writer_json_stdout_default(self):
|
|
189
181
|
output = nextmv.Output(
|
|
@@ -262,7 +254,7 @@ class TestOutput(unittest.TestCase):
|
|
|
262
254
|
|
|
263
255
|
self.assertEqual(
|
|
264
256
|
mock_stdout.getvalue(),
|
|
265
|
-
'{"assets":[],"
|
|
257
|
+
'{"assets":[],"options":{},"solution":{"empanadas":"are_life"},"statistics":{"foo":"bar"}}\n',
|
|
266
258
|
)
|
|
267
259
|
|
|
268
260
|
def test_local_writer_json_stdout_with_options(self):
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import json
|
|
3
|
+
import unittest
|
|
4
|
+
|
|
5
|
+
import nextmv.serialization
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestSerialization(unittest.TestCase):
|
|
9
|
+
"""Tests for the common serialization functionality."""
|
|
10
|
+
|
|
11
|
+
def test_default_serialization(self):
|
|
12
|
+
"""Test the default serialization"""
|
|
13
|
+
|
|
14
|
+
data = {
|
|
15
|
+
"name": "Test",
|
|
16
|
+
"value": 42,
|
|
17
|
+
"timestamp": nextmv.serialization._custom_serial(datetime.datetime(2023, 10, 1)),
|
|
18
|
+
}
|
|
19
|
+
serialized = nextmv.serialization.serialize_json(data)
|
|
20
|
+
expected = json.dumps(
|
|
21
|
+
{
|
|
22
|
+
"name": "Test",
|
|
23
|
+
"value": 42,
|
|
24
|
+
"timestamp": "2023-10-01T00:00:00",
|
|
25
|
+
},
|
|
26
|
+
separators=(",", ":"),
|
|
27
|
+
)
|
|
28
|
+
self.assertEqual(serialized, expected)
|
|
29
|
+
|
|
30
|
+
def test_custom_serialization(self):
|
|
31
|
+
"""Test custom serialization with additional configurations"""
|
|
32
|
+
|
|
33
|
+
data = {
|
|
34
|
+
"name": "Test",
|
|
35
|
+
"value": 42,
|
|
36
|
+
"timestamp": nextmv.serialization._custom_serial(datetime.datetime(2023, 10, 1)),
|
|
37
|
+
}
|
|
38
|
+
json_configurations = {
|
|
39
|
+
"indent": 2,
|
|
40
|
+
"default": nextmv.serialization._custom_serial,
|
|
41
|
+
"separators": (",", ": "),
|
|
42
|
+
}
|
|
43
|
+
serialized = nextmv.serialization.serialize_json(data, json_configurations)
|
|
44
|
+
expected = json.dumps(
|
|
45
|
+
{
|
|
46
|
+
"name": "Test",
|
|
47
|
+
"value": 42,
|
|
48
|
+
"timestamp": "2023-10-01T00:00:00",
|
|
49
|
+
},
|
|
50
|
+
indent=2,
|
|
51
|
+
separators=(",", ": "),
|
|
52
|
+
)
|
|
53
|
+
self.assertEqual(serialized, expected)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "v0.28.2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|