FourCIPP 1.1.0__py3-none-any.whl → 1.3.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/config/4C_metadata.yaml +672 -1
- fourcipp/config/4C_schema.json +6514 -5070
- fourcipp/fourc_input.py +77 -5
- fourcipp/utils/configuration.py +4 -3
- fourcipp/utils/dict_utils.py +32 -0
- fourcipp/utils/yaml_io.py +18 -8
- fourcipp/version.py +2 -2
- {fourcipp-1.1.0.dist-info → fourcipp-1.3.0.dist-info}/METADATA +2 -2
- {fourcipp-1.1.0.dist-info → fourcipp-1.3.0.dist-info}/RECORD +13 -13
- {fourcipp-1.1.0.dist-info → fourcipp-1.3.0.dist-info}/WHEEL +0 -0
- {fourcipp-1.1.0.dist-info → fourcipp-1.3.0.dist-info}/entry_points.txt +0 -0
- {fourcipp-1.1.0.dist-info → fourcipp-1.3.0.dist-info}/licenses/LICENSE +0 -0
- {fourcipp-1.1.0.dist-info → fourcipp-1.3.0.dist-info}/top_level.txt +0 -0
fourcipp/fourc_input.py
CHANGED
|
@@ -27,7 +27,7 @@ import copy
|
|
|
27
27
|
import difflib
|
|
28
28
|
import pathlib
|
|
29
29
|
from collections.abc import Sequence
|
|
30
|
-
from typing import Any
|
|
30
|
+
from typing import Any, Callable
|
|
31
31
|
|
|
32
32
|
from loguru import logger
|
|
33
33
|
|
|
@@ -37,7 +37,10 @@ from fourcipp.legacy_io import (
|
|
|
37
37
|
interpret_legacy_section,
|
|
38
38
|
)
|
|
39
39
|
from fourcipp.utils.converter import Converter
|
|
40
|
-
from fourcipp.utils.dict_utils import
|
|
40
|
+
from fourcipp.utils.dict_utils import (
|
|
41
|
+
compare_nested_dicts_or_lists,
|
|
42
|
+
sort_by_key_order,
|
|
43
|
+
)
|
|
41
44
|
from fourcipp.utils.not_set import NotSet, check_if_set
|
|
42
45
|
from fourcipp.utils.typing import Path
|
|
43
46
|
from fourcipp.utils.validation import ValidationError, validate_using_json_schema
|
|
@@ -66,6 +69,75 @@ def is_section_known(section_name: str, known_section_names: list[str]) -> bool:
|
|
|
66
69
|
return section_name in known_section_names or section_name.startswith("FUNCT")
|
|
67
70
|
|
|
68
71
|
|
|
72
|
+
def _sort_by_section_names(data: dict) -> dict:
|
|
73
|
+
"""Sort a dictionary by its 4C sections.
|
|
74
|
+
|
|
75
|
+
This sorts the dictionary in the following style:
|
|
76
|
+
|
|
77
|
+
1. "TITLE" section
|
|
78
|
+
2. Alphabetically sorted sections
|
|
79
|
+
3. Alphabetically sorted legacy sections
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
data: Dictionary to sort.
|
|
83
|
+
section_names: List of all section names in the 4C style order.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Dict sorted in 4C fashion
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
required_sections = CONFIG.fourc_json_schema["required"]
|
|
90
|
+
n_sections_splitter = len(CONFIG.sections.all_sections) * 1000
|
|
91
|
+
|
|
92
|
+
# collect typed sections + numeric FUNCT sections
|
|
93
|
+
typed_and_funct = sorted(
|
|
94
|
+
sorted(CONFIG.sections.typed_sections, key=str.lower)
|
|
95
|
+
+ [s for s in data.keys() if s.startswith("FUNCT") and s[5:].isdigit()],
|
|
96
|
+
key=lambda s: (
|
|
97
|
+
s.lower() if not s.startswith("FUNCT") else f"funct{s[5:].zfill(10)}"
|
|
98
|
+
),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def ordering_score(section: str) -> int:
|
|
102
|
+
"""Get ordering score, small score comes first, larger comes later.
|
|
103
|
+
|
|
104
|
+
We offset the score by the number of sections multiplied by 1000. This way a score is guaranteed to never appear twice.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
section: Section name to score
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
ordering score
|
|
111
|
+
"""
|
|
112
|
+
# Title sections
|
|
113
|
+
if section == CONFIG.fourc_metadata["metadata"]["description_section_name"]:
|
|
114
|
+
return 0
|
|
115
|
+
# Required sections
|
|
116
|
+
elif section in required_sections:
|
|
117
|
+
return 1 * n_sections_splitter + required_sections.index(section)
|
|
118
|
+
# Typed + FUNCT sections (alphabetical + case insensitive)
|
|
119
|
+
elif section in typed_and_funct:
|
|
120
|
+
return 2 * n_sections_splitter + typed_and_funct.index(section)
|
|
121
|
+
# Legacy sections
|
|
122
|
+
elif section in CONFIG.sections.legacy_sections:
|
|
123
|
+
return 3 * n_sections_splitter + CONFIG.sections.legacy_sections.index(
|
|
124
|
+
section
|
|
125
|
+
)
|
|
126
|
+
# Unknown section
|
|
127
|
+
else:
|
|
128
|
+
raise KeyError(f"Unknown section {section}")
|
|
129
|
+
|
|
130
|
+
unknown_sections = set(data.keys()) - set(CONFIG.sections.all_sections)
|
|
131
|
+
|
|
132
|
+
# Remove functions, these are a special case
|
|
133
|
+
if [section for section in unknown_sections if not section.startswith("FUNCT")]:
|
|
134
|
+
raise ValueError(
|
|
135
|
+
f"Sections {list(unknown_sections)} are not known in 'section_names'"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
return sort_by_key_order(data, sorted(data.keys(), key=ordering_score))
|
|
139
|
+
|
|
140
|
+
|
|
69
141
|
class FourCInput:
|
|
70
142
|
"""4C inout file object."""
|
|
71
143
|
|
|
@@ -420,20 +492,20 @@ class FourCInput:
|
|
|
420
492
|
def dump(
|
|
421
493
|
self,
|
|
422
494
|
input_file_path: Path,
|
|
423
|
-
sort_sections: bool = False,
|
|
424
495
|
validate: bool = False,
|
|
425
496
|
validate_sections_only: bool = False,
|
|
426
497
|
convert_to_native_types: bool = True,
|
|
498
|
+
sort_function: Callable[[dict], dict] | None = _sort_by_section_names,
|
|
427
499
|
) -> None:
|
|
428
500
|
"""Dump object to yaml.
|
|
429
501
|
|
|
430
502
|
Args:
|
|
431
503
|
input_file_path: Path to dump the data to
|
|
432
|
-
sort_sections: Sort the sections alphabetically
|
|
433
504
|
validate: Validate input data before dumping
|
|
434
505
|
validate_sections_only: Validate each section independently.
|
|
435
506
|
Requiredness of the sections themselves is ignored.
|
|
436
507
|
convert_to_native_types: Convert all sections to native Python types
|
|
508
|
+
sort_function: Function to sort the sections.
|
|
437
509
|
"""
|
|
438
510
|
|
|
439
511
|
if validate or validate_sections_only:
|
|
@@ -448,7 +520,7 @@ class FourCInput:
|
|
|
448
520
|
if convert_to_native_types:
|
|
449
521
|
self.convert_to_native_types()
|
|
450
522
|
|
|
451
|
-
dump_yaml(self.inlined, input_file_path,
|
|
523
|
+
dump_yaml(self.inlined, input_file_path, sort_function)
|
|
452
524
|
|
|
453
525
|
def validate(
|
|
454
526
|
self,
|
fourcipp/utils/configuration.py
CHANGED
|
@@ -45,7 +45,7 @@ class Sections:
|
|
|
45
45
|
"""
|
|
46
46
|
self.legacy_sections: list[str] = legacy_sections
|
|
47
47
|
self.typed_sections: list[str] = typed_sections
|
|
48
|
-
self.all_sections: list[str] =
|
|
48
|
+
self.all_sections: list[str] = typed_sections + legacy_sections
|
|
49
49
|
|
|
50
50
|
@classmethod
|
|
51
51
|
def from_metadata(cls, fourc_metadata: dict) -> Sections:
|
|
@@ -58,9 +58,10 @@ class Sections:
|
|
|
58
58
|
Sections: sections object
|
|
59
59
|
"""
|
|
60
60
|
description_section = fourc_metadata["metadata"]["description_section_name"]
|
|
61
|
-
sections = [
|
|
61
|
+
sections = [description_section] + [
|
|
62
62
|
section["name"] for section in fourc_metadata["sections"]["specs"]
|
|
63
|
-
]
|
|
63
|
+
]
|
|
64
|
+
|
|
64
65
|
legacy_sections = list(fourc_metadata["legacy_string_sections"])
|
|
65
66
|
|
|
66
67
|
return cls(legacy_sections, sections)
|
fourcipp/utils/dict_utils.py
CHANGED
|
@@ -373,3 +373,35 @@ def rename_parameter(
|
|
|
373
373
|
|
|
374
374
|
for entry, last_key in _split_off_last_key(nested_dict, keys):
|
|
375
375
|
entry[new_name] = entry.pop(last_key)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def sort_by_key_order(data: dict, key_order: list[str]) -> dict:
|
|
379
|
+
"""Sort a dictionary by a specific key order.
|
|
380
|
+
|
|
381
|
+
Args:
|
|
382
|
+
data: Dictionary to sort.
|
|
383
|
+
key_order: List of keys in the desired order.
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
Sorted dictionary.
|
|
387
|
+
"""
|
|
388
|
+
if set(key_order) != set(data.keys()):
|
|
389
|
+
raise ValueError("'key_order' must include all keys in the dictionary!")
|
|
390
|
+
|
|
391
|
+
return {key: data[key] for key in key_order if key in data}
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def sort_alphabetically(
|
|
395
|
+
data: dict,
|
|
396
|
+
) -> dict:
|
|
397
|
+
"""Sort a dictionary alphabetically.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
data: Dictionary to sort.
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
Sorted dictionary.
|
|
404
|
+
"""
|
|
405
|
+
return sort_by_key_order(
|
|
406
|
+
data, sorted(data.keys(), key=lambda s: (s.lower(), 0 if s.islower() else 1))
|
|
407
|
+
)
|
fourcipp/utils/yaml_io.py
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import json
|
|
25
25
|
import pathlib
|
|
26
26
|
import re
|
|
27
|
+
from typing import Callable
|
|
27
28
|
|
|
28
29
|
import ryml
|
|
29
30
|
|
|
@@ -61,17 +62,21 @@ def load_yaml(path_to_yaml_file: Path) -> dict:
|
|
|
61
62
|
return data
|
|
62
63
|
|
|
63
64
|
|
|
64
|
-
def dict_to_yaml_string(
|
|
65
|
+
def dict_to_yaml_string(
|
|
66
|
+
data: dict, sort_function: Callable[[dict], dict] | None = None
|
|
67
|
+
) -> str:
|
|
65
68
|
"""Dump dict as yaml.
|
|
66
69
|
|
|
67
70
|
Args:
|
|
68
71
|
data: Data to dump.
|
|
69
|
-
|
|
72
|
+
sort_function: Function to sort the data.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
YAML string representation of the data
|
|
70
76
|
"""
|
|
71
77
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
data = {key: data[key] for key in sorted(data.keys())}
|
|
78
|
+
if sort_function is not None:
|
|
79
|
+
data = sort_function(data)
|
|
75
80
|
|
|
76
81
|
# Convert dictionary into a ryml tree
|
|
77
82
|
tree = ryml.parse_in_arena(bytearray(json.dumps(data).encode("utf8")))
|
|
@@ -88,14 +93,19 @@ def dict_to_yaml_string(data: dict, sort_keys: bool = False) -> str:
|
|
|
88
93
|
return ryml.emit_yaml(tree)
|
|
89
94
|
|
|
90
95
|
|
|
91
|
-
def dump_yaml(
|
|
96
|
+
def dump_yaml(
|
|
97
|
+
data: dict,
|
|
98
|
+
path_to_yaml_file: Path,
|
|
99
|
+
sort_function: Callable[[dict], dict] | None = None,
|
|
100
|
+
) -> None:
|
|
92
101
|
"""Dump yaml to file.
|
|
93
102
|
|
|
94
103
|
Args:
|
|
95
104
|
data: Data to dump.
|
|
96
105
|
path_to_yaml_file: Yaml file path
|
|
97
|
-
|
|
106
|
+
sort_function: Function to sort the data.
|
|
98
107
|
"""
|
|
99
108
|
pathlib.Path(path_to_yaml_file).write_text(
|
|
100
|
-
dict_to_yaml_string(data,
|
|
109
|
+
dict_to_yaml_string(data, sort_function),
|
|
110
|
+
encoding="utf-8",
|
|
101
111
|
)
|
fourcipp/version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.
|
|
32
|
-
__version_tuple__ = version_tuple = (1,
|
|
31
|
+
__version__ = version = '1.3.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 3, 0)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: FourCIPP
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: A streamlined Python Parser for 4C input files
|
|
5
5
|
Author: FourCIPP Authors
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -168,7 +168,7 @@ input_4C["PROBLEM SIZE"]["NODES"] = 10_000_000
|
|
|
168
168
|
removed_section = input_4C.pop("PROBLEM SIZE")
|
|
169
169
|
|
|
170
170
|
# Dump to file
|
|
171
|
-
input_4C.dump(input_file_path,
|
|
171
|
+
input_4C.dump(input_file_path, validate=True)
|
|
172
172
|
```
|
|
173
173
|
<!--example, do not remove this comment-->
|
|
174
174
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
fourcipp/__init__.py,sha256=4pz7DVXErSbUcLqPTaHnQfdJzKkpfZDivBqbHbTgpRE,1388
|
|
2
|
-
fourcipp/fourc_input.py,sha256=
|
|
3
|
-
fourcipp/version.py,sha256=
|
|
4
|
-
fourcipp/config/4C_metadata.yaml,sha256=
|
|
5
|
-
fourcipp/config/4C_schema.json,sha256=
|
|
2
|
+
fourcipp/fourc_input.py,sha256=w37dzvfuzGXv0EdzfGABKjmAwxx-4Ba7dTyzjyk_ApI,23803
|
|
3
|
+
fourcipp/version.py,sha256=0Oc4EBzGTJOvXX0Vym4evglW1NQPpe8RLn8TdxsKzfs,704
|
|
4
|
+
fourcipp/config/4C_metadata.yaml,sha256=3n3Uj24iblvsfqUI-8H2LYMHOROjeHl68Nok0F22Unc,11868927
|
|
5
|
+
fourcipp/config/4C_schema.json,sha256=67giZGZSKXkjO_NCbZzx-blVdGB6BFXRbHrXkmqB_T4,16412275
|
|
6
6
|
fourcipp/config/config.yaml,sha256=n2c2a6E4HKfAdNWOQz1kLUuf5p4NLxIddaAi2t5eM38,460
|
|
7
7
|
fourcipp/legacy_io/__init__.py,sha256=y6aTjgUe61OQSl1NMiZ-fQAGTab_xNT1eJTnaTnsIkc,5744
|
|
8
8
|
fourcipp/legacy_io/element.py,sha256=b8--f3IR9nB68R25mk4DHHOBdDLqASewtAdPZAkA2t4,3971
|
|
@@ -12,17 +12,17 @@ fourcipp/legacy_io/node_topology.py,sha256=hqGGzhyNhFX-BMW8SzztfzM8zoZLLltVScMv-
|
|
|
12
12
|
fourcipp/legacy_io/particle.py,sha256=0rxwdiMnHI1QUGZPqWgsxqyslrxB7aq7qxgNMb_y_rk,2166
|
|
13
13
|
fourcipp/utils/__init__.py,sha256=ccdlf4taJ0mKLg_ru8ilXEa72PoO9N2UIxHNHDEtQmY,1151
|
|
14
14
|
fourcipp/utils/cli.py,sha256=43Nmy9tnoQzwWMZwpktWVv3T3a3y4qDzfuDB1bHogbA,4658
|
|
15
|
-
fourcipp/utils/configuration.py,sha256=
|
|
15
|
+
fourcipp/utils/configuration.py,sha256=HDrvHrH4K5mdienzVsAt_sh9j2Pv81bxWBqqbeNb1KE,6461
|
|
16
16
|
fourcipp/utils/converter.py,sha256=D40YQ96WqPEEpB7fwAB5XC2v-jRki4v1sIJ-ngO08nU,5194
|
|
17
|
-
fourcipp/utils/dict_utils.py,sha256=
|
|
17
|
+
fourcipp/utils/dict_utils.py,sha256=uC0uaBNP3Wh2v3kFy9JHnAYARMukAN4cl40pmiBT13Y,12891
|
|
18
18
|
fourcipp/utils/metadata.py,sha256=98jz9Gm8qdvZ-b1jwYObNJTaiMQWwbknvS70Nv6Gwhk,1291
|
|
19
19
|
fourcipp/utils/not_set.py,sha256=04C_3axe2cupBYgfpgDAcGs1zHVzG3I58UGO58TH05A,2017
|
|
20
20
|
fourcipp/utils/typing.py,sha256=8iX9PuKe8B1WJ3vEjiM5ZfefvgYnaZDiSdB7Nx9SrVw,1625
|
|
21
21
|
fourcipp/utils/validation.py,sha256=FejHOj1MddaU7gEpMN-f8Mz3rYjflakd1qcsKnctHqA,5292
|
|
22
|
-
fourcipp/utils/yaml_io.py,sha256=
|
|
23
|
-
fourcipp-1.
|
|
24
|
-
fourcipp-1.
|
|
25
|
-
fourcipp-1.
|
|
26
|
-
fourcipp-1.
|
|
27
|
-
fourcipp-1.
|
|
28
|
-
fourcipp-1.
|
|
22
|
+
fourcipp/utils/yaml_io.py,sha256=yShbQ7d_zv_tGK_3ym3NilrfL7HpsEt_8JvDqZYnuFY,3606
|
|
23
|
+
fourcipp-1.3.0.dist-info/licenses/LICENSE,sha256=lkSOHdH9IZ8c3Vnz0fFjqls1cRlmLADBP8QEIwUlH3o,1082
|
|
24
|
+
fourcipp-1.3.0.dist-info/METADATA,sha256=4G6YxfZlgnnDMV19Yz3UblMfxHpnMCAqWonlpsgmdcY,7947
|
|
25
|
+
fourcipp-1.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
26
|
+
fourcipp-1.3.0.dist-info/entry_points.txt,sha256=44XBG4bwhuq1EwOZ0U055HYP8_qN6_d30ecVsa5Igng,53
|
|
27
|
+
fourcipp-1.3.0.dist-info/top_level.txt,sha256=oZ6jgFFmvi157VwGUEFuKT3D8oS5mOkpOVx8zZURZrQ,9
|
|
28
|
+
fourcipp-1.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|