Skip to content

Commit b09d9bf

Browse files
authored
Merge pull request #46 from ialarmedalien/fix_list_file_input
Fix `generate` method to work with lists and dicts
2 parents 7a2c72d + 3e274be commit b09d9bf

File tree

2 files changed

+66
-67
lines changed

2 files changed

+66
-67
lines changed

json_to_models/generator.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ def generate(self, *data_variants: dict) -> dict:
4646
"""
4747
Convert given list of data variants to metadata dict
4848
"""
49+
if isinstance(data_variants[0], list):
50+
data_variants = [item for sublist in data_variants for item in sublist]
4951
fields_sets = [self._convert(data) for data in data_variants]
5052
fields = self.merge_field_sets(fields_sets)
5153
return self.optimize_type(fields)
@@ -54,13 +56,13 @@ def _convert(self, data: dict):
5456
"""
5557
Key and string value converting
5658
"""
57-
fields = dict()
59+
fields = {}
5860
for key, value in data.items():
5961
if not isinstance(key, str):
60-
raise TypeError(f'You probably using some not JSON-compatible parser and have some {type(key)} as dict key. '
62+
raise TypeError(f'You are probably using a parser that is not JSON compatible and have data with some {type(key)}s as dict keys. '
6163
f'This is not supported.\n'
6264
f'Context: {data}\n'
63-
f'(If you parsing yaml try to replace PyYaml with ruamel.yaml)')
65+
f'(If you are parsing yaml, try replacing PyYaml with ruamel.yaml)')
6466
convert_dict = key not in self.dict_keys_fields
6567
fields[key] = self._detect_type(value, convert_dict)
6668
return fields

test/test_code_generation/test_models_composition.py

Lines changed: 61 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from typing import Dict, List, Set, Tuple
2-
1+
from typing import Dict, List, Set, Tuple, Union, Any
2+
from copy import deepcopy
33
import pytest
44

55
from json_to_models.dynamic_typing import ModelMeta
@@ -21,71 +21,70 @@ def test_list_ex():
2121
assert l == [0, 'a', *range(1, 6), 'b', *range(6, 10)]
2222

2323

24+
def generate_list_input(input_dict: Dict[str, Any]) -> Dict[str, Any]:
25+
"""
26+
Convert input into a list format.
27+
28+
Mimics the case where the JSON in a file has a list
29+
at the top level, rather than a dictionary.
30+
31+
:param input_dict: dict with keys 'value', 'expected', and 'id'
32+
:type input_dict: dict
33+
:return: duplicate of the input structure but with the 'value' value as a list
34+
:rtype: dict
35+
"""
36+
outputs = {
37+
"expected": deepcopy(input_dict["expected"]),
38+
"id": input_dict["id"] + "_list",
39+
"value": []
40+
}
41+
42+
for item in input_dict["value"]:
43+
# item is a tuple of model name and model data
44+
model = [{key: deepcopy(value)} for key, value in item[1].items()]
45+
outputs["value"].append((item[0], model))
46+
47+
return outputs
48+
49+
2450
# This test relies on model names as a some sort of models ids
2551
# and may fail if some logic of their generation will be changed
2652
# List of Tuple[root_model_name, JSON data] | Dict[model_name, Set[root_model_names]]
27-
test_extract_root_data = [
28-
pytest.param(
29-
[
30-
("TestModelA", {
31-
"count": 1,
32-
"items": [
33-
{
34-
"x": .5,
35-
"y": .1
36-
}
37-
]
38-
}),
39-
("TestModelB", {
40-
"next": "some_url",
41-
"prev": None,
42-
"count": 2000,
43-
"items": [
44-
{
45-
"x": .5,
46-
"y": .1
47-
}
48-
]
49-
}),
53+
extract_root_data_input = [
54+
{
55+
"value": [
56+
("TestModelA", {"count": 1, "items": [{"x": 0.5, "y": 0.1}]}),
57+
(
58+
"TestModelB",
59+
{
60+
"next": "some_url",
61+
"prev": None,
62+
"count": 2000,
63+
"items": [{"x": 0.5, "y": 0.1}],
64+
},
65+
),
5066
],
51-
{
52-
'Item': {'TestModelA', 'TestModelB'},
53-
'TestModelA': set()
54-
}
55-
),
56-
pytest.param(
57-
[
58-
("TestModelA", {
59-
"count": 1,
60-
"items": [
61-
{
62-
"x": .5,
63-
"y": .1
64-
}
65-
]
66-
}),
67-
("TestModelB", {
68-
"count": 1,
69-
"items": [
70-
{
71-
"x": .5,
72-
"y": .1
73-
}
74-
]
75-
}),
67+
"expected": {"Item": {"TestModelA", "TestModelB"}, "TestModelA": set()},
68+
"id": "separate_roots"
69+
},{
70+
"value": [
71+
("TestModelA", {"count": 1, "items": [{"x": 0.5, "y": 0.1}]}),
72+
("TestModelB", {"count": 1, "items": [{"x": 0.5, "y": 0.1}]}),
7673
],
77-
{
78-
'Item': {'TestModelA_TestModelB'},
79-
'TestModelA_TestModelB': set()
80-
},
81-
id="merge_root"
82-
)
83-
]
74+
"expected": {"Item": {"TestModelA_TestModelB"}, "TestModelA_TestModelB": set()},
75+
"id": "merge_root",
76+
}]
8477

78+
extract_root_data_input_list = [generate_list_input(i) for i in extract_root_data_input]
79+
test_extract_root_data = [pytest.param(inpt["value"], inpt["expected"], id=inpt["id"]) for inpt in extract_root_data_input + extract_root_data_input_list]
8580

8681
@pytest.mark.parametrize("value,expected", test_extract_root_data)
87-
def test_extract_root(models_generator: MetadataGenerator, models_registry: ModelRegistry,
88-
value: List[Tuple[str, dict]], expected: Dict[str, Set[str]]):
82+
def test_extract_root(
83+
models_generator: MetadataGenerator,
84+
models_registry: ModelRegistry,
85+
value: List[Tuple[str, Union[dict, list]]],
86+
expected: Dict[str, Set[str]],
87+
):
8988
for model_name, data in value:
9089
fields = models_generator.generate(data)
9190
models_registry.process_meta_data(fields, model_name=model_name)
@@ -103,7 +102,7 @@ def test_extract_root(models_generator: MetadataGenerator, models_registry: Mode
103102

104103

105104
def _test_compose_models(
106-
function, request,
105+
function,
107106
models_generator: MetadataGenerator, models_registry: ModelRegistry,
108107
value: List[Tuple[str, dict]], expected: List[Tuple[str, list]], expected_mapping: Dict[str, str]
109108
):
@@ -299,11 +298,10 @@ def check(nested_value: List[dict], nested_expected: List[Tuple[str, list]]):
299298

300299
@pytest.mark.parametrize("value,expected,expected_mapping", test_compose_models_data)
301300
def test_compose_models(
302-
request,
303301
models_generator: MetadataGenerator, models_registry: ModelRegistry,
304302
value: List[Tuple[str, dict]], expected: List[Tuple[str, list]], expected_mapping: Dict[str, str]
305303
):
306-
_test_compose_models(compose_models, request, models_generator, models_registry, value, expected, expected_mapping)
304+
_test_compose_models(compose_models, models_generator, models_registry, value, expected, expected_mapping)
307305

308306

309307
test_compose_models_flat_data = [
@@ -606,9 +604,8 @@ def test_compose_models(
606604

607605
@pytest.mark.parametrize("value,expected,expected_mapping", test_compose_models_flat_data)
608606
def test_compose_models_flat(
609-
request,
610607
models_generator: MetadataGenerator, models_registry: ModelRegistry,
611608
value: List[Tuple[str, dict]], expected: List[Tuple[str, list]], expected_mapping: Dict[str, str]
612609
):
613-
_test_compose_models(compose_models_flat, request, models_generator, models_registry, value, expected,
610+
_test_compose_models(compose_models_flat, models_generator, models_registry, value, expected,
614611
expected_mapping)

0 commit comments

Comments
 (0)