Skip to content

Commit 1852aa9

Browse files
maximilian-techMaximilian Sander
authored and
Maximilian Sander
committed
Extend parsing of Scientific Notation to JSON capabilites
1 parent 117a31d commit 1852aa9

File tree

4 files changed

+42
-9
lines changed

4 files changed

+42
-9
lines changed

src/datamodel_code_generator/__init__.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
PythonVersionMin,
3131
)
3232
from datamodel_code_generator.parser import DefaultPutDict, LiteralType
33-
from datamodel_code_generator.util import SafeLoader
33+
from datamodel_code_generator.util import SafeLoader, get_safeloader
3434

3535
MIN_VERSION: Final[int] = 9
3636
MAX_VERSION: Final[int] = 13
@@ -46,9 +46,14 @@
4646

4747
DEFAULT_BASE_CLASS: str = "pydantic.BaseModel"
4848

49+
g_extend_yaml_scientifc_notation: bool = False
50+
51+
def get_safeloader_wrapper(safeloader: type[SafeLoader]) -> type[SafeLoader]:
52+
return get_safeloader(safeloader, extend_yaml_scientifc_notation=g_extend_yaml_scientifc_notation)
53+
4954

5055
def load_yaml(stream: str | TextIO) -> Any:
51-
return yaml.load(stream, Loader=SafeLoader) # noqa: S506
56+
return yaml.load(stream, Loader=get_safeloader_wrapper(SafeLoader)) # noqa: S506
5257

5358

5459
def load_yaml_from_path(path: Path, encoding: str) -> Any:
@@ -262,6 +267,7 @@ def generate( # noqa: PLR0912, PLR0913, PLR0914, PLR0915
262267
use_title_as_name: bool = False,
263268
use_operation_id_as_name: bool = False,
264269
use_unique_items_as_set: bool = False,
270+
extend_yaml_scientifc_notation: bool = False,
265271
http_headers: Sequence[tuple[str, str]] | None = None,
266272
http_ignore_tls: bool = False,
267273
use_annotated: bool = False,
@@ -288,6 +294,8 @@ def generate( # noqa: PLR0912, PLR0913, PLR0914, PLR0915
288294
no_alias: bool = False,
289295
formatters: list[Formatter] = DEFAULT_FORMATTERS,
290296
) -> None:
297+
global g_extend_yaml_scientifc_notation
298+
g_extend_yaml_scientifc_notation = extend_yaml_scientifc_notation
291299
remote_text_cache: DefaultPutDict[str, str] = DefaultPutDict()
292300
if isinstance(input_, str):
293301
input_text: str | None = input_

src/datamodel_code_generator/__main__.py

+2
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ def validate_root(cls, values: Any) -> Any: # noqa: N805
290290
use_title_as_name: bool = False
291291
use_operation_id_as_name: bool = False
292292
use_unique_items_as_set: bool = False
293+
extend_yaml_scientifc_notation: bool = False
293294
http_headers: Optional[Sequence[tuple[str, str]]] = None # noqa: UP045
294295
http_ignore_tls: bool = False
295296
use_annotated: bool = False
@@ -498,6 +499,7 @@ def main(args: Sequence[str] | None = None) -> Exit: # noqa: PLR0911, PLR0912,
498499
use_title_as_name=config.use_title_as_name,
499500
use_operation_id_as_name=config.use_operation_id_as_name,
500501
use_unique_items_as_set=config.use_unique_items_as_set,
502+
extend_yaml_scientifc_notation=config.extend_yaml_scientifc_notation,
501503
http_headers=config.http_headers,
502504
http_ignore_tls=config.http_ignore_tls,
503505
use_annotated=config.use_annotated,

src/datamodel_code_generator/arguments.py

+6
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,12 @@ def start_section(self, heading: str | None) -> None:
286286
action="store_true",
287287
default=None,
288288
)
289+
typing_options.add_argument(
290+
"--extend-yaml-scientifc-notation",
291+
help="Parse scientific floating point as specified by json instead of yaml.",
292+
action="store_true",
293+
default=None,
294+
)
289295

290296
# ======================================================================================
291297
# Customization options for generated model fields

src/datamodel_code_generator/util.py

+24-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import copy
4+
import re
45
from typing import TYPE_CHECKING, Any, Callable, TypeVar
56

67
import pydantic
@@ -34,14 +35,30 @@ def load_toml(path: Path) -> dict[str, Any]:
3435
with path.open("rb") as f:
3536
return load_tomllib(f)
3637

38+
def get_safeloader(safeloader: type[SafeLoader], *, extend_yaml_scientifc_notation: bool) -> type[SafeLoader]:
39+
safeloadertemp = copy.deepcopy(safeloader)
40+
safeloadertemp.yaml_constructors = copy.deepcopy(safeloader.yaml_constructors)
41+
safeloadertemp.add_constructor(
42+
"tag:yaml.org,2002:timestamp",
43+
safeloadertemp.yaml_constructors["tag:yaml.org,2002:str"],
44+
)
45+
if extend_yaml_scientifc_notation is True:
46+
safeloadertemp.add_implicit_resolver(
47+
"tag:yaml.org,2002:float",
48+
re.compile(
49+
r"""^(?:
50+
[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?
51+
|[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)
52+
|\\.[0-9_]+(?:[eE][-+][0-9]+)?
53+
|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*
54+
|[-+]?\\.(?:inf|Inf|INF)
55+
|\\.(?:nan|NaN|NAN))$""",
56+
re.VERBOSE,
57+
),
58+
list("-+0123456789."),
59+
)
60+
return safeloadertemp
3761

38-
SafeLoaderTemp = copy.deepcopy(SafeLoader)
39-
SafeLoaderTemp.yaml_constructors = copy.deepcopy(SafeLoader.yaml_constructors)
40-
SafeLoaderTemp.add_constructor(
41-
"tag:yaml.org,2002:timestamp",
42-
SafeLoaderTemp.yaml_constructors["tag:yaml.org,2002:str"],
43-
)
44-
SafeLoader = SafeLoaderTemp
4562

4663
Model = TypeVar("Model", bound=_BaseModel)
4764

0 commit comments

Comments
 (0)