Skip to content

Commit cdd4413

Browse files
authored
Merge pull request #51 from bogdandm/cli-disable-string-fields-feature
CLI: Add option to unregister string serializable fields
2 parents bbf2f80 + 63ce3cb commit cdd4413

File tree

4 files changed

+47
-6
lines changed

4 files changed

+47
-6
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,11 @@ Arguments:
568568
* **Example**: `--code-generator-kwargs kwarg1=true kwarg2=10 "kwarg3=It is string with spaces"`
569569
* **Optional**
570570

571-
One of model arguments (`-m` or `-l`) is required.
571+
* `--disable-str-serializable-types` - List of python types for which StringSerializable should be disabled.
572+
Alternatively you could use the name of StringSerializable subclass itself (i.e. IntString).
573+
* **Format**: `--disable-str-serializable-types [TYPE [TYPE ...]]`
574+
* **Example**: `--disable-str-serializable-types float int BooleanString IsoDatetimeString`
575+
* **Optional**
572576

573577
### Low level API
574578

json_to_models/cli.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
yaml = None
2121

2222
from . import __version__ as VERSION
23-
from .dynamic_typing import ModelMeta, register_datetime_classes
23+
from .dynamic_typing import ModelMeta, register_datetime_classes, registry
2424
from .generator import MetadataGenerator
2525
from .models import ModelsStructureType
2626
from .models.attr import AttrsModelCodeGenerator
@@ -96,6 +96,9 @@ def parse_args(self, args: List[str] = None):
9696
dict_keys_fields: List[str] = namespace.dict_keys_fields
9797
preamble: str = namespace.preamble
9898

99+
for name in namespace.disable_str_serializable_types:
100+
registry.remove_by_name(name)
101+
99102
self.setup_models_data(namespace.model or (), namespace.list or (), parser)
100103
self.validate(merge_policy, framework, code_generator)
101104
self.set_args(merge_policy, structure, framework, code_generator, code_generator_kwargs_raw,
@@ -367,6 +370,16 @@ def _create_argparser(cls) -> argparse.ArgumentParser:
367370
type=str,
368371
help="Code to insert into the generated file after the imports and before the list of classes\n\n"
369372
)
373+
parser.add_argument(
374+
"--disable-str-serializable-types",
375+
metavar="TYPE",
376+
default=[],
377+
nargs="*", type=str,
378+
help="List of python types for which StringSerializable should be disabled, i.e:\n"
379+
"--disable-str-serializable-types float int\n"
380+
"Alternatively you could use the name of StringSerializable subclass itself (i.e. IntString)"
381+
"\n\n"
382+
)
370383
parser.add_argument(
371384
"-l", "--list",
372385
nargs=3, action="append", metavar=("<Model name>", "<JSON lookup>", "<JSON file>"),

json_to_models/dynamic_typing/string_serializable.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def decorator(cls):
8686

8787
return decorator
8888

89-
def remove(self, cls: type):
89+
def remove(self, cls: T_StringSerializable):
9090
"""
9191
Unregister given class
9292
@@ -97,6 +97,11 @@ def remove(self, cls: type):
9797
if replace is cls or base is cls:
9898
self.replaces.remove((base, replace))
9999

100+
def remove_by_name(self, name: str):
101+
for cls in self.types[:]:
102+
if cls.__name__ == name or cls.actual_type.__name__ == name:
103+
self.remove(cls)
104+
100105
def resolve(self, *types: T_StringSerializable) -> Collection[T_StringSerializable]:
101106
"""
102107
Return set of StringSerializable classes which can represent all classes from types argument.

test/test_cli/test_script.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import imp
22
import json
3+
import re
34
import subprocess
45
import sys
56
import tempfile
@@ -94,7 +95,7 @@ def test_help():
9495
]
9596

9697

97-
def execute_test(command, output_file: Path = None, output=None) -> Tuple[str, str]:
98+
def execute_test(command, output_file: Path = None, output=None) -> str:
9899
proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
99100
stdout, stderr = map(bytes.decode, proc.communicate())
100101
if output_file:
@@ -172,7 +173,6 @@ def test_script_custom(command):
172173

173174
@pytest.mark.parametrize("command", test_commands)
174175
def test_add_preamble(command):
175-
176176
PREAMBLE_TEXT = """
177177
# this is some test code
178178
# to be added to the file
@@ -187,8 +187,13 @@ def test_add_preamble(command):
187187

188188

189189
@pytest.mark.parametrize("command", test_commands)
190-
def test_add_trim_preamble(command):
190+
def test_disable_some_string_types_smoke(command):
191+
command += " --disable-str-serializable-types float int"
192+
execute_test(command)
191193

194+
195+
@pytest.mark.parametrize("command", test_commands)
196+
def test_add_trim_preamble(command):
192197
def trim_header(line_string):
193198
"""remove the quoted command and everything from the first class declaration onwards"""
194199
lines = line_string.splitlines()
@@ -247,3 +252,17 @@ def test_script_output_file(command):
247252
file = tmp_path / 'out.py'
248253
command += f" -o {file}"
249254
execute_test(command, output_file=file)
255+
256+
257+
cmds = [
258+
pytest.param(f"""{executable} -m User "{test_data_path / 'users.json'}" -f pydantic --disable-str-serializable-types float int""",
259+
id="users")
260+
]
261+
262+
263+
@pytest.mark.parametrize("command", cmds)
264+
def test_disable_some_string_types(command):
265+
stdout = execute_test(command)
266+
assert 'lat: str' in stdout
267+
assert 'lng: str' in stdout
268+
assert not any(re.match(r'\s+zipcode:.+int.+', line) for line in stdout.split('\n')), "zipcode should not be parsed as int"

0 commit comments

Comments
 (0)