Change BaseModel.parse_file to use Config.json_loads (#1069)

fix #1067

* Making json_loads available to parse_file

* Change BaseModel.parse_file to use Config.json_loads

* Update changes/1067-kierandarcy.md

Co-Authored-By: Samuel Colvin <samcolvin@gmail.com>

* Fixed some style issues and added missing test for parse_file_as
This commit is contained in:
Kieran Darcy
2019-12-03 15:05:27 +00:00
committed by Samuel Colvin
parent d059fded52
commit 9982eb43dd
6 changed files with 54 additions and 3 deletions
+1
View File
@@ -0,0 +1 @@
Change `BaseModel.parse_file` to use `Config.json_loads`
+8 -1
View File
@@ -425,7 +425,14 @@ class BaseModel(metaclass=ModelMetaclass):
proto: Protocol = None,
allow_pickle: bool = False,
) -> 'Model':
obj = load_file(path, proto=proto, content_type=content_type, encoding=encoding, allow_pickle=allow_pickle)
obj = load_file(
path,
proto=proto,
content_type=content_type,
encoding=encoding,
allow_pickle=allow_pickle,
json_loads=cls.__config__.json_loads,
)
return cls.parse_obj(obj)
@classmethod
+4 -1
View File
@@ -51,6 +51,7 @@ def load_file(
encoding: str = 'utf8',
proto: Protocol = None,
allow_pickle: bool = False,
json_loads: Callable[[str], Any] = json.loads,
) -> Any:
path = Path(path)
b = path.read_bytes()
@@ -60,4 +61,6 @@ def load_file(
elif path.suffix == '.pkl':
proto = Protocol.pickle
return load_str_bytes(b, proto=proto, content_type=content_type, encoding=encoding, allow_pickle=allow_pickle)
return load_str_bytes(
b, proto=proto, content_type=content_type, encoding=encoding, allow_pickle=allow_pickle, json_loads=json_loads,
)
+10 -1
View File
@@ -1,3 +1,4 @@
import json
from functools import lru_cache
from pathlib import Path
from typing import Any, Callable, Optional, Type, TypeVar, Union
@@ -42,7 +43,15 @@ def parse_file_as(
encoding: str = 'utf8',
proto: Protocol = None,
allow_pickle: bool = False,
json_loads: Callable[[str], Any] = json.loads,
type_name: Optional[NameFactory] = None,
) -> T:
obj = load_file(path, proto=proto, content_type=content_type, encoding=encoding, allow_pickle=allow_pickle)
obj = load_file(
path,
proto=proto,
content_type=content_type,
encoding=encoding,
allow_pickle=allow_pickle,
json_loads=json_loads,
)
return parse_obj_as(type_, obj, type_name=type_name)
+19
View File
@@ -1,3 +1,4 @@
import json
import pickle
from typing import List, Union
@@ -106,6 +107,24 @@ def test_file_json_no_ext(tmpdir):
assert Model.parse_file(str(p)) == Model(a=12, b=8)
def test_file_json_loads(tmp_path):
def custom_json_loads(*args, **kwargs):
data = json.loads(*args, **kwargs)
data['a'] = 99
return data
class Example(BaseModel):
a: int
class Config:
json_loads = custom_json_loads
p = tmp_path / 'test_json_loads.json'
p.write_text('{"a": 12}')
assert Example.parse_file(p) == Example(a=99)
def test_file_pickle(tmpdir):
p = tmpdir.join('test.pkl')
p.write_binary(pickle.dumps(dict(a=12, b=8)))
+12
View File
@@ -1,3 +1,4 @@
import json
from typing import Dict, List, Mapping
import pytest
@@ -76,3 +77,14 @@ def test_parse_file_as(tmp_path):
p = tmp_path / 'test.json'
p.write_text('{"1": "2"}')
assert parse_file_as(Dict[int, int], p) == {1: 2}
def test_parse_file_as_json_loads(tmp_path):
def custom_json_loads(*args, **kwargs):
data = json.loads(*args, **kwargs)
data[1] = 99
return data
p = tmp_path / 'test_json_loads.json'
p.write_text('{"1": "2"}')
assert parse_file_as(Dict[int, int], p, json_loads=custom_json_loads) == {1: 99}