FourCIPP 1.50.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fourcipp/__init__.py +34 -0
- fourcipp/config/4C_metadata.yaml +63447 -0
- fourcipp/config/4C_schema.json +402481 -0
- fourcipp/config/config.yaml +12 -0
- fourcipp/fourc_input.py +697 -0
- fourcipp/legacy_io/__init__.py +162 -0
- fourcipp/legacy_io/element.py +135 -0
- fourcipp/legacy_io/inline_dat.py +224 -0
- fourcipp/legacy_io/node.py +114 -0
- fourcipp/legacy_io/node_topology.py +194 -0
- fourcipp/legacy_io/particle.py +71 -0
- fourcipp/utils/__init__.py +22 -0
- fourcipp/utils/cli.py +168 -0
- fourcipp/utils/configuration.py +222 -0
- fourcipp/utils/converter.py +138 -0
- fourcipp/utils/dict_utils.py +407 -0
- fourcipp/utils/metadata.py +1017 -0
- fourcipp/utils/not_set.py +77 -0
- fourcipp/utils/type_hinting.py +44 -0
- fourcipp/utils/validation.py +155 -0
- fourcipp/utils/yaml_io.py +172 -0
- fourcipp/version.py +34 -0
- fourcipp-1.50.0.dist-info/METADATA +225 -0
- fourcipp-1.50.0.dist-info/RECORD +28 -0
- fourcipp-1.50.0.dist-info/WHEEL +5 -0
- fourcipp-1.50.0.dist-info/entry_points.txt +2 -0
- fourcipp-1.50.0.dist-info/licenses/LICENSE +21 -0
- fourcipp-1.50.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# The MIT License (MIT)
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025 FourCIPP Authors
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
|
13
|
+
# all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
# THE SOFTWARE.
|
|
22
|
+
"""Not set utils."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class NotSet:
|
|
26
|
+
"""Not set object."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, expected: object = object) -> None:
|
|
29
|
+
"""Not set object.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
expected: Expected object to to display
|
|
33
|
+
"""
|
|
34
|
+
self.expected = expected
|
|
35
|
+
|
|
36
|
+
def __str__(self) -> str: # pragma: no cover
|
|
37
|
+
"""String method."""
|
|
38
|
+
return f"NotSet({self.expected})"
|
|
39
|
+
|
|
40
|
+
def __repr__(self) -> str: # pragma: no cover
|
|
41
|
+
"""Representation method."""
|
|
42
|
+
return f"NotSet({self.expected})"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
NOT_SET = NotSet()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def check_if_set(obj: object) -> bool:
|
|
49
|
+
"""Check if object or is NotSet.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
obj: Object to check
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
True if object is set
|
|
56
|
+
"""
|
|
57
|
+
# Check if object is not of type _NotSet, i.e. it has a value
|
|
58
|
+
return not isinstance(obj, NotSet)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def pop_arguments(key: str, default: object = NOT_SET) -> tuple:
|
|
62
|
+
"""Create arguments for the pop method.
|
|
63
|
+
|
|
64
|
+
We need this utility since pop is not implemented using kwargs, instead the default is checked
|
|
65
|
+
via the number of arguments.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
key: Key to pop the value for
|
|
69
|
+
default: Default value to return in case of the pop value.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Arguments for pop
|
|
73
|
+
"""
|
|
74
|
+
if check_if_set(default):
|
|
75
|
+
return (key, default)
|
|
76
|
+
else:
|
|
77
|
+
return (key,)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# The MIT License (MIT)
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025 FourCIPP Authors
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
|
13
|
+
# all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
# THE SOFTWARE.
|
|
22
|
+
"""Type hinting utils."""
|
|
23
|
+
|
|
24
|
+
import pathlib
|
|
25
|
+
from collections.abc import Callable
|
|
26
|
+
from typing import TypeAlias, TypeVar
|
|
27
|
+
|
|
28
|
+
from fourcipp.utils.not_set import NotSet
|
|
29
|
+
|
|
30
|
+
# Generic type variable
|
|
31
|
+
T = TypeVar("T")
|
|
32
|
+
|
|
33
|
+
# For paths we commonly use string or pathlib.path
|
|
34
|
+
Path: TypeAlias = pathlib.Path | str
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# For casting dicts
|
|
38
|
+
Extractor: TypeAlias = Callable[[str], T]
|
|
39
|
+
LineListExtractor: TypeAlias = Callable[[list[str]], T]
|
|
40
|
+
LineCastingDict: TypeAlias = dict[str, LineListExtractor]
|
|
41
|
+
NestedCastingDict: TypeAlias = dict[str, LineCastingDict | LineListExtractor]
|
|
42
|
+
|
|
43
|
+
# NotSet
|
|
44
|
+
NotSetAlias: TypeAlias = NotSet | T
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# The MIT License (MIT)
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025 FourCIPP Authors
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
|
13
|
+
# all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
# THE SOFTWARE.
|
|
22
|
+
"""Validation utils."""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import sys
|
|
27
|
+
from collections.abc import Iterable, Sequence
|
|
28
|
+
|
|
29
|
+
import jsonschema_rs
|
|
30
|
+
|
|
31
|
+
from fourcipp.utils.yaml_io import dict_to_yaml_string
|
|
32
|
+
|
|
33
|
+
MAX_INT = 2_147_483_647 # C++ value
|
|
34
|
+
MAX_FLOAT = sys.float_info.max
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ValidationError(Exception):
|
|
38
|
+
"""FourCIPP validation error."""
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def path_indexer(path: Sequence[str | int]) -> str:
|
|
42
|
+
"""Create a path representation to walk the dict."""
|
|
43
|
+
path_for_data = ""
|
|
44
|
+
for p in path:
|
|
45
|
+
if isinstance(p, str):
|
|
46
|
+
p = '"' + p + '"'
|
|
47
|
+
path_for_data += "[" + str(p) + "]"
|
|
48
|
+
return path_for_data
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def indent(text: str, n_spaces: int = 4) -> str:
|
|
52
|
+
"""Indent the text."""
|
|
53
|
+
indent_with_newline = "\n" + " " * n_spaces
|
|
54
|
+
return indent_with_newline + text.replace("\n", indent_with_newline)
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def from_schema_validation_errors(
|
|
58
|
+
cls, errors: Iterable[jsonschema_rs.ValidationError]
|
|
59
|
+
) -> ValidationError:
|
|
60
|
+
"""Create error from multiple errors.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
errors: Errors to raise
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
New error for this case
|
|
67
|
+
"""
|
|
68
|
+
message = "\nValidation failed, due to the following parameters:"
|
|
69
|
+
|
|
70
|
+
for error in errors:
|
|
71
|
+
message += "\n\n- Parameter in " + cls.path_indexer(error.instance_path)
|
|
72
|
+
message += cls.indent(cls.indent(dict_to_yaml_string(error.instance), 4))
|
|
73
|
+
message += cls.indent("Error: " + error.message, 2)
|
|
74
|
+
|
|
75
|
+
return cls(message)
|
|
76
|
+
|
|
77
|
+
@classmethod
|
|
78
|
+
def from_overflow_errors(
|
|
79
|
+
cls, object_paths_with_errors: Iterable[tuple[list[str | int], int | float]]
|
|
80
|
+
) -> ValidationError:
|
|
81
|
+
"""Create error from multiple errors.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
errors: Errors to raise
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
New error for this case
|
|
88
|
+
"""
|
|
89
|
+
message = "\nValidation failed, due to the following parameters:"
|
|
90
|
+
|
|
91
|
+
for path, obj in object_paths_with_errors:
|
|
92
|
+
message += "\n\n- Parameter in " + cls.path_indexer(path)
|
|
93
|
+
message += cls.indent(cls.indent(str(obj), 4))
|
|
94
|
+
|
|
95
|
+
if isinstance(obj, int):
|
|
96
|
+
error = f"Maximum int value {MAX_INT} exceeded"
|
|
97
|
+
else:
|
|
98
|
+
error = f"Maximum float value {MAX_FLOAT} exceeded"
|
|
99
|
+
message += cls.indent("Error: " + error, 2)
|
|
100
|
+
|
|
101
|
+
return cls(message)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def find_keys_exceeding_max_value(
|
|
105
|
+
obj: object, path_for_data: list[str | int] | None = None
|
|
106
|
+
) -> Iterable[tuple[list[str | int], int | float]]:
|
|
107
|
+
"""Find entries exceeding max values.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
obj (object): Object to check
|
|
111
|
+
path_for_data: Path to the data
|
|
112
|
+
|
|
113
|
+
Yields:
|
|
114
|
+
path for each case where this problem emerges
|
|
115
|
+
"""
|
|
116
|
+
if path_for_data is None:
|
|
117
|
+
path_for_data = []
|
|
118
|
+
|
|
119
|
+
if isinstance(obj, dict):
|
|
120
|
+
for key, value in obj.items():
|
|
121
|
+
yield from find_keys_exceeding_max_value(value, path_for_data + [key])
|
|
122
|
+
elif isinstance(obj, list):
|
|
123
|
+
for index, item in enumerate(obj):
|
|
124
|
+
yield from find_keys_exceeding_max_value(item, path_for_data + [index])
|
|
125
|
+
elif isinstance(obj, int) and abs(obj) > MAX_INT:
|
|
126
|
+
yield path_for_data, obj
|
|
127
|
+
elif isinstance(obj, float) and abs(obj) > MAX_FLOAT:
|
|
128
|
+
yield path_for_data, obj
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def validate_using_json_schema(data: dict, json_schema: dict) -> bool:
|
|
132
|
+
"""Validate data using a JSON schema.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
data: Data to validate
|
|
136
|
+
json_schema: Schema for validation
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
True if successful
|
|
140
|
+
"""
|
|
141
|
+
validator = jsonschema_rs.validator_for(json_schema)
|
|
142
|
+
try:
|
|
143
|
+
validator.validate(data)
|
|
144
|
+
except jsonschema_rs.ValidationError as exception:
|
|
145
|
+
# Validation failed, look for all errors
|
|
146
|
+
raise ValidationError.from_schema_validation_errors(
|
|
147
|
+
validator.iter_errors(data)
|
|
148
|
+
) from exception
|
|
149
|
+
except ValueError as exception:
|
|
150
|
+
if str(exception).endswith("too big to convert"):
|
|
151
|
+
raise ValidationError.from_overflow_errors(
|
|
152
|
+
find_keys_exceeding_max_value(data)
|
|
153
|
+
) from exception
|
|
154
|
+
raise
|
|
155
|
+
return True
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# The MIT License (MIT)
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025 FourCIPP Authors
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
|
13
|
+
# all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
# THE SOFTWARE.
|
|
22
|
+
"""YAML io."""
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import pathlib
|
|
26
|
+
from typing import Callable
|
|
27
|
+
|
|
28
|
+
import regex
|
|
29
|
+
import ryml
|
|
30
|
+
|
|
31
|
+
from fourcipp.utils.type_hinting import Path
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def load_yaml(path_to_yaml_file: Path) -> dict:
|
|
35
|
+
"""Load yaml files.
|
|
36
|
+
|
|
37
|
+
rapidyaml is the fastest yaml parsing library we could find. Since it returns custom objects we
|
|
38
|
+
use the library to emit the objects to json and subsequently read it in using the json library.
|
|
39
|
+
This is still two orders of magnitude faster compared to other yaml libraries.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
path_to_yaml_file: Path to yaml file
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Loaded data
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
json_str = ryml.emit_json(
|
|
49
|
+
ryml.parse_in_arena(pathlib.Path(path_to_yaml_file).read_bytes())
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Convert `inf` to a string to avoid JSON parsing errors, see https://github.com/biojppm/rapidyaml/issues/312
|
|
53
|
+
json_str = regex.sub(r":\s*(-?)inf\b", r': "\1inf"', json_str)
|
|
54
|
+
|
|
55
|
+
# Convert floats that are missing digits on either side of the decimal point
|
|
56
|
+
# so .5 to 0.5 and 5. to 5.0
|
|
57
|
+
json_str = regex.sub(r":\s*(-?)\.([0-9]+)", r": \g<1>0.\2", json_str)
|
|
58
|
+
json_str = regex.sub(r":\s*(-?)([0-9]+)\.(\D)", r": \1\2.0\3", json_str)
|
|
59
|
+
|
|
60
|
+
data = json.loads(json_str)
|
|
61
|
+
|
|
62
|
+
return data
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def dict_to_yaml_string(
|
|
66
|
+
data: dict,
|
|
67
|
+
sort_function: Callable[[dict], dict] | None = None,
|
|
68
|
+
use_fourcipp_yaml_style: bool = True,
|
|
69
|
+
) -> str:
|
|
70
|
+
"""Dump dict as yaml.
|
|
71
|
+
|
|
72
|
+
The FourCIPP yaml style sets flow
|
|
73
|
+
Args:
|
|
74
|
+
data: Data to dump.
|
|
75
|
+
sort_function: Function to sort the data.
|
|
76
|
+
use_fourcipp_yaml_style: If FourCIPP yaml style is to be used
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
YAML string representation of the data
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
if sort_function is not None:
|
|
83
|
+
data = sort_function(data)
|
|
84
|
+
|
|
85
|
+
# Convert dictionary into a ryml tree
|
|
86
|
+
tree = ryml.parse_in_arena(bytearray(json.dumps(data).encode("utf8")))
|
|
87
|
+
|
|
88
|
+
def check_is_vector(tree: ryml.Tree, node_id: int) -> bool:
|
|
89
|
+
"""Check if sequence is of ints, floats or sequence there of.
|
|
90
|
+
|
|
91
|
+
In 4C metadata terms, list of strings, bools, etc. could also be vectors.
|
|
92
|
+
For the sake of simplicity these are omitted.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
tree (ryml.Tree): Tree to check
|
|
96
|
+
node_id (int): Node id
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
returns if entry is a vector
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
for sub_node, _ in ryml.walk(tree, node_id):
|
|
103
|
+
# Ignore the root node
|
|
104
|
+
if sub_node == node_id:
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
# If sequence contains a dict
|
|
108
|
+
if tree.is_map(sub_node):
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
# If sequence contains a sequence
|
|
112
|
+
elif tree.is_seq(sub_node):
|
|
113
|
+
if not check_is_vector(tree, sub_node):
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
# Else it's a value
|
|
117
|
+
else:
|
|
118
|
+
val = tree.val(sub_node).tobytes().decode("ascii")
|
|
119
|
+
is_not_numeric = (
|
|
120
|
+
tree.is_val_quoted(sub_node) # string
|
|
121
|
+
or tree.val_is_null(sub_node) # null
|
|
122
|
+
or val == "true" # bool
|
|
123
|
+
or val == "false" # bool
|
|
124
|
+
)
|
|
125
|
+
if is_not_numeric:
|
|
126
|
+
return False
|
|
127
|
+
|
|
128
|
+
return True
|
|
129
|
+
|
|
130
|
+
# Change style bits to avoid JSON output and format vectors correctly
|
|
131
|
+
# see https://github.com/biojppm/rapidyaml/issues/520
|
|
132
|
+
for node_id, depth in ryml.walk(tree):
|
|
133
|
+
if tree.is_map(node_id):
|
|
134
|
+
tree.set_container_style(node_id, ryml.NOTYPE)
|
|
135
|
+
elif tree.is_seq(node_id):
|
|
136
|
+
if (
|
|
137
|
+
not use_fourcipp_yaml_style # do not do special formatting
|
|
138
|
+
or depth == 1 # is a section
|
|
139
|
+
or not check_is_vector(tree, node_id) # is not a vector
|
|
140
|
+
):
|
|
141
|
+
tree.set_container_style(node_id, ryml.NOTYPE)
|
|
142
|
+
|
|
143
|
+
if tree.has_key(node_id):
|
|
144
|
+
tree.set_key_style(node_id, ryml.NOTYPE)
|
|
145
|
+
|
|
146
|
+
yaml_string = ryml.emit_yaml(tree)
|
|
147
|
+
|
|
148
|
+
if use_fourcipp_yaml_style:
|
|
149
|
+
# add spaces after commas in vectors
|
|
150
|
+
yaml_string = regex.sub(r"(?<=\d),(?=\d)|(?<=\]),(?=\[)", ", ", yaml_string)
|
|
151
|
+
|
|
152
|
+
return yaml_string
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def dump_yaml(
|
|
156
|
+
data: dict,
|
|
157
|
+
path_to_yaml_file: Path,
|
|
158
|
+
sort_function: Callable[[dict], dict] | None = None,
|
|
159
|
+
use_fourcipp_yaml_style: bool = True,
|
|
160
|
+
) -> None:
|
|
161
|
+
"""Dump yaml to file.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
data: Data to dump.
|
|
165
|
+
path_to_yaml_file: Yaml file path
|
|
166
|
+
sort_function: Function to sort the data
|
|
167
|
+
use_fourcipp_yaml_style: If FourCIPP yaml style is to be used
|
|
168
|
+
"""
|
|
169
|
+
pathlib.Path(path_to_yaml_file).write_text(
|
|
170
|
+
dict_to_yaml_string(data, sort_function, use_fourcipp_yaml_style),
|
|
171
|
+
encoding="utf-8",
|
|
172
|
+
)
|
fourcipp/version.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '1.50.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 50, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|