Skip to content

Commit 09b7b5d

Browse files
committed
Fix unicode conversion bugs and add self-validate pydantic test
1 parent 62d0f3e commit 09b7b5d

File tree

3 files changed

+63
-8
lines changed

3 files changed

+63
-8
lines changed

json_to_models/generator.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import re
22
from typing import Any, Callable, List, Optional, Pattern, Union
33

4-
from unidecode import unidecode
5-
64
from .dynamic_typing import (
75
ComplexType,
86
DDict,
@@ -58,12 +56,8 @@ def _convert(self, data: dict):
5856
"""
5957
fields = dict()
6058
for key, value in data.items():
61-
# TODO: Check if is 0xC0000005 crash has a place at linux systems
62-
# ! _detect_type function can crash at some complex data sets if value is unicode with some characters (maybe German)
63-
# Crash does not produce any useful logs and can occur any time after bad string was processed
64-
# It can be reproduced on real_apis tests (openlibrary API)
6559
convert_dict = key not in self.dict_keys_fields
66-
fields[key] = self._detect_type(value if not isinstance(value, str) else unidecode(value), convert_dict)
60+
fields[key] = self._detect_type(value, convert_dict)
6761
return fields
6862

6963
def _detect_type(self, value, convert_dict=True) -> MetaData:

json_to_models/models/base.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ def _generate_code(
220220
"""
221221
imports = []
222222
classes = []
223+
generators = []
223224
for data in structure:
224225
nested_imports, nested_classes = _generate_code(
225226
data["nested"],
@@ -228,7 +229,11 @@ def _generate_code(
228229
lvl=lvl + 1
229230
)
230231
imports.extend(nested_imports)
231-
gen = class_generator(data["model"], **class_generator_kwargs)
232+
generators.append((
233+
class_generator(data["model"], **class_generator_kwargs),
234+
nested_classes
235+
))
236+
for gen, nested_classes in generators:
232237
cls_imports, cls_string = gen.generate(nested_classes)
233238
imports.extend(cls_imports)
234239
classes.append(cls_string)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import imp
2+
import json
3+
import sys
4+
from inspect import isclass
5+
6+
import pydantic
7+
import pytest
8+
9+
from json_to_models.generator import MetadataGenerator
10+
from json_to_models.models.base import generate_code
11+
from json_to_models.models.pydantic import PydanticModelCodeGenerator
12+
from json_to_models.models.structure import compose_models_flat
13+
from json_to_models.registry import ModelRegistry
14+
from .test_script import test_data_path
15+
16+
test_self_validate_pydantic_data = [
17+
pytest.param(test_data_path / "gists.json", list, id="gists.json"),
18+
pytest.param(test_data_path / "users.json", list, id="users.json"),
19+
pytest.param(test_data_path / "unicode.json", dict, id="unicode.json"),
20+
pytest.param(test_data_path / "photos.json", dict, id="photos.json"),
21+
]
22+
23+
24+
@pytest.mark.parametrize("data,data_type", test_self_validate_pydantic_data)
25+
def test_self_validate_pydantic(data, data_type):
26+
with data.open() as f:
27+
data = json.load(f)
28+
29+
gen = MetadataGenerator(
30+
dict_keys_fields=['files']
31+
)
32+
reg = ModelRegistry()
33+
if data_type is not list:
34+
data = [data]
35+
fields = gen.generate(*data)
36+
reg.process_meta_data(fields, model_name="TestModel")
37+
reg.merge_models(generator=gen)
38+
reg.generate_names()
39+
40+
structure = compose_models_flat(reg.models_map)
41+
code = generate_code(structure, PydanticModelCodeGenerator)
42+
module = imp.new_module("test_models")
43+
sys.modules["test_models"] = module
44+
try:
45+
exec(compile(code, "test_models.py", "exec"), module.__dict__)
46+
except Exception as e:
47+
assert not e, code
48+
49+
import test_models
50+
for name in dir(test_models):
51+
cls = getattr(test_models, name)
52+
if isclass(cls) and issubclass(cls, pydantic.BaseModel):
53+
cls.update_forward_refs()
54+
for item in data:
55+
obj = test_models.TestModel.parse_obj(item)
56+
assert obj

0 commit comments

Comments
 (0)