python-table-converter 0.2.4__tar.gz → 0.2.5__tar.gz
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.
- {python_table_converter-0.2.4 → python_table_converter-0.2.5}/PKG-INFO +1 -1
- {python_table_converter-0.2.4 → python_table_converter-0.2.5}/pyproject.toml +1 -1
- python_table_converter-0.2.5/table_converter/__init__.py +2 -0
- python_table_converter-0.2.5/table_converter/core/config.py +123 -0
- {python_table_converter-0.2.4 → python_table_converter-0.2.5}/table_converter/core/convert.py +12 -78
- python_table_converter-0.2.5/table_converter/core/functions/assign_id.py +108 -0
- python_table_converter-0.2.5/table_converter/core/functions/get_field_value.py +15 -0
- python_table_converter-0.2.5/table_converter/core/functions/search_column_value.py +28 -0
- python_table_converter-0.2.5/table_converter/core/functions/set_field_value.py +18 -0
- python_table_converter-0.2.4/table_converter/__init__.py +0 -2
- python_table_converter-0.2.4/table_converter/core/config.py +0 -71
- {python_table_converter-0.2.4 → python_table_converter-0.2.5}/LICENSE +0 -0
- {python_table_converter-0.2.4 → python_table_converter-0.2.5}/README.md +0 -0
- {python_table_converter-0.2.4 → python_table_converter-0.2.5}/table_converter/cli.py +0 -0
- {python_table_converter-0.2.4 → python_table_converter-0.2.5}/table_converter/commands/convert_tables.py +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
import dataclasses
|
|
5
|
+
from typing import Mapping
|
|
6
|
+
|
|
7
|
+
from icecream import ic
|
|
8
|
+
import yaml
|
|
9
|
+
|
|
10
|
+
type FlatFieldMap = Mapping[str, str]
|
|
11
|
+
type FieldMap = Mapping[str, str|FieldMap]
|
|
12
|
+
|
|
13
|
+
@dataclasses.dataclass
|
|
14
|
+
class AssignIdConfig:
|
|
15
|
+
primary: list[str]
|
|
16
|
+
#given: list[str] | None = None
|
|
17
|
+
context: list[str] | None = None
|
|
18
|
+
|
|
19
|
+
@dataclasses.dataclass
|
|
20
|
+
class ProcessConfig:
|
|
21
|
+
assign_constants: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
|
|
22
|
+
assign_formats: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
|
|
23
|
+
#assign_ids: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
|
|
24
|
+
assign_ids: Mapping[str, AssignIdConfig] = dataclasses.field(default_factory=OrderedDict)
|
|
25
|
+
split_by_newline: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
|
|
26
|
+
|
|
27
|
+
def __setitem__(self, key, value):
|
|
28
|
+
setattr(self, key, value)
|
|
29
|
+
|
|
30
|
+
@dataclasses.dataclass
|
|
31
|
+
class Config:
|
|
32
|
+
map: FieldMap = dataclasses.field(default_factory=OrderedDict)
|
|
33
|
+
process: ProcessConfig = dataclasses.field(default_factory=ProcessConfig)
|
|
34
|
+
|
|
35
|
+
def flatten(
|
|
36
|
+
mapping: FieldMap,
|
|
37
|
+
parent_key: str = '',
|
|
38
|
+
new_mapping: FlatFieldMap | None = None,
|
|
39
|
+
) -> FlatFieldMap:
|
|
40
|
+
if new_mapping is None:
|
|
41
|
+
new_mapping = OrderedDict()
|
|
42
|
+
for key, mapped in mapping.items():
|
|
43
|
+
new_key = f'{parent_key}.{key}' if parent_key else key
|
|
44
|
+
if isinstance(mapped, Mapping):
|
|
45
|
+
flatten(mapped, new_key, new_mapping)
|
|
46
|
+
else:
|
|
47
|
+
new_mapping[new_key] = mapped
|
|
48
|
+
return new_mapping
|
|
49
|
+
|
|
50
|
+
def setup_config(
|
|
51
|
+
config_path: str | None = None,
|
|
52
|
+
):
|
|
53
|
+
config = Config()
|
|
54
|
+
if config_path:
|
|
55
|
+
if config_path.endswith('.yaml'):
|
|
56
|
+
yaml.add_constructor(
|
|
57
|
+
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
|
|
58
|
+
lambda loader, node: OrderedDict(loader.construct_pairs(node)),
|
|
59
|
+
)
|
|
60
|
+
with open(config_path, 'r') as f:
|
|
61
|
+
loaded = yaml.load(f, yaml.Loader)
|
|
62
|
+
else:
|
|
63
|
+
raise ValueError(
|
|
64
|
+
'Only YAML configuration files are supported.'
|
|
65
|
+
)
|
|
66
|
+
ic(loaded)
|
|
67
|
+
if 'map' in loaded:
|
|
68
|
+
config.map = flatten(loaded['map'])
|
|
69
|
+
setup_process_config(config, loaded)
|
|
70
|
+
return config
|
|
71
|
+
|
|
72
|
+
def setup_process_config(
|
|
73
|
+
config: Config,
|
|
74
|
+
loaded: Mapping,
|
|
75
|
+
):
|
|
76
|
+
dict_process = loaded.get('process')
|
|
77
|
+
if isinstance(dict_process, Mapping):
|
|
78
|
+
for process_key in [
|
|
79
|
+
'assign_constants',
|
|
80
|
+
'assign_formats',
|
|
81
|
+
'split_by_newline',
|
|
82
|
+
]:
|
|
83
|
+
dict_subprocess = dict_process.get(process_key)
|
|
84
|
+
if isinstance(dict_subprocess, Mapping):
|
|
85
|
+
config.process[process_key] = flatten(loaded['process'][process_key])
|
|
86
|
+
setup_process_assign_ids_config(config, dict_process)
|
|
87
|
+
|
|
88
|
+
def setup_process_assign_ids_config(
|
|
89
|
+
config: Config,
|
|
90
|
+
dict_process: Mapping,
|
|
91
|
+
):
|
|
92
|
+
dict_subprocess = dict_process.get('assign_ids')
|
|
93
|
+
if isinstance(dict_subprocess, Mapping):
|
|
94
|
+
for key, value in dict_subprocess.items():
|
|
95
|
+
if isinstance(value, Mapping):
|
|
96
|
+
primary = value.get('primary')
|
|
97
|
+
if not primary:
|
|
98
|
+
ic.enable()
|
|
99
|
+
ic(value)
|
|
100
|
+
ic(value.get('primary'))
|
|
101
|
+
raise ValueError(
|
|
102
|
+
'Primary field is required for assign_ids.'
|
|
103
|
+
)
|
|
104
|
+
config.process.assign_ids[key] = AssignIdConfig(
|
|
105
|
+
primary = value.get('primary', []),
|
|
106
|
+
#given = value.get('given', None),
|
|
107
|
+
context = value.get('context', None),
|
|
108
|
+
)
|
|
109
|
+
elif isinstance(value, list):
|
|
110
|
+
config.process.assign_ids[key] = AssignIdConfig(
|
|
111
|
+
primary = value,
|
|
112
|
+
)
|
|
113
|
+
elif isinstance(value, str):
|
|
114
|
+
config.process.assign_ids[key] = AssignIdConfig(
|
|
115
|
+
primary = [value],
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
ic.enable()
|
|
119
|
+
ic(value)
|
|
120
|
+
ic(type(value))
|
|
121
|
+
raise ValueError(
|
|
122
|
+
f'Unsupported assign_ids value type: {type(value)}'
|
|
123
|
+
)
|
{python_table_converter-0.2.4 → python_table_converter-0.2.5}/table_converter/core/convert.py
RENAMED
|
@@ -14,6 +14,13 @@ import pandas as pd
|
|
|
14
14
|
# local
|
|
15
15
|
|
|
16
16
|
from . config import setup_config
|
|
17
|
+
from . functions.assign_id import (
|
|
18
|
+
assign_id,
|
|
19
|
+
create_id_context_map,
|
|
20
|
+
setup_assign_ids,
|
|
21
|
+
)
|
|
22
|
+
from . functions.get_field_value import get_field_value
|
|
23
|
+
from . functions.set_field_value import set_field_value
|
|
17
24
|
|
|
18
25
|
dict_loaders: dict[str, callable] = {}
|
|
19
26
|
def register_loader(
|
|
@@ -85,31 +92,6 @@ def save_jsonl(
|
|
|
85
92
|
)
|
|
86
93
|
f.write('\n')
|
|
87
94
|
|
|
88
|
-
def set_field_value(
|
|
89
|
-
data: OrderedDict,
|
|
90
|
-
field: str,
|
|
91
|
-
value: any,
|
|
92
|
-
):
|
|
93
|
-
if '.' in field:
|
|
94
|
-
field, rest = field.split('.', 1)
|
|
95
|
-
if field not in data:
|
|
96
|
-
data[field] = OrderedDict()
|
|
97
|
-
set_field_value(data[field], rest, value)
|
|
98
|
-
else:
|
|
99
|
-
data[field] = value
|
|
100
|
-
|
|
101
|
-
def get_field_value(
|
|
102
|
-
data: OrderedDict,
|
|
103
|
-
field: str,
|
|
104
|
-
):
|
|
105
|
-
if field in data:
|
|
106
|
-
return data[field], True
|
|
107
|
-
if '.' in field:
|
|
108
|
-
field, rest = field.split('.', 1)
|
|
109
|
-
if field in data:
|
|
110
|
-
return get_field_value(data[field], rest)
|
|
111
|
-
return None, False
|
|
112
|
-
|
|
113
95
|
def search_column_value(
|
|
114
96
|
row: OrderedDict,
|
|
115
97
|
column: str,
|
|
@@ -159,7 +141,7 @@ def map_formats(
|
|
|
159
141
|
#ic(e.args)
|
|
160
142
|
#ic(e.args[0])
|
|
161
143
|
key = e.args[0]
|
|
162
|
-
params[key] = '__undefined__'
|
|
144
|
+
params[key] = f'__{key}__undefined__'
|
|
163
145
|
except:
|
|
164
146
|
raise
|
|
165
147
|
set_field_value(new_row, f'__debug__.{column}', formatted)
|
|
@@ -196,46 +178,6 @@ def apply_fields_split_by_newline(
|
|
|
196
178
|
set_field_value(new_row, f'__debug__.{column}', value)
|
|
197
179
|
return new_row
|
|
198
180
|
|
|
199
|
-
def create_id_stat_node():
|
|
200
|
-
return {
|
|
201
|
-
'max_id': 0,
|
|
202
|
-
'dict_value_to_id': {},
|
|
203
|
-
'dict_id_to_node': {},
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
def assign_id_in_node(
|
|
207
|
-
row: OrderedDict,
|
|
208
|
-
column: str,
|
|
209
|
-
dict_assignment: OrderedDict,
|
|
210
|
-
id_stat_node: dict,
|
|
211
|
-
):
|
|
212
|
-
value, found = search_column_value(row, dict_assignment[column])
|
|
213
|
-
if not found:
|
|
214
|
-
raise KeyError(f'Column not found: {column}, existing columns: {row.keys()}')
|
|
215
|
-
if value not in id_stat_node['dict_value_to_id']:
|
|
216
|
-
field_id = id_stat_node['max_id'] + 1
|
|
217
|
-
id_stat_node['max_id'] = field_id
|
|
218
|
-
id_stat_node['dict_value_to_id'][value] = field_id
|
|
219
|
-
node = create_id_stat_node()
|
|
220
|
-
id_stat_node['dict_id_to_node'][field_id] = node
|
|
221
|
-
else:
|
|
222
|
-
field_id = id_stat_node['dict_value_to_id'][value]
|
|
223
|
-
node = id_stat_node['dict_id_to_node'][field_id]
|
|
224
|
-
set_field_value(row, f'__debug__.{column}', field_id)
|
|
225
|
-
set_field_value(row, f'__debug__.__ids__.{column}', field_id)
|
|
226
|
-
return node
|
|
227
|
-
|
|
228
|
-
def assign_id(
|
|
229
|
-
row: OrderedDict,
|
|
230
|
-
dict_assignment: OrderedDict,
|
|
231
|
-
root_id_stat_node: dict,
|
|
232
|
-
):
|
|
233
|
-
new_row = OrderedDict(row)
|
|
234
|
-
node = root_id_stat_node
|
|
235
|
-
for column in dict_assignment:
|
|
236
|
-
node = assign_id_in_node(new_row, column, dict_assignment, node)
|
|
237
|
-
return new_row
|
|
238
|
-
|
|
239
181
|
def convert(
|
|
240
182
|
input_files: list[str],
|
|
241
183
|
output_file: str | None = None,
|
|
@@ -251,8 +193,7 @@ def convert(
|
|
|
251
193
|
ic()
|
|
252
194
|
ic(input_files)
|
|
253
195
|
df_list = []
|
|
254
|
-
|
|
255
|
-
root_id_stat = create_id_stat_node()
|
|
196
|
+
id_context_map = create_id_context_map()
|
|
256
197
|
config = setup_config(config_path)
|
|
257
198
|
ic(config)
|
|
258
199
|
if assign_constants:
|
|
@@ -288,14 +229,7 @@ def convert(
|
|
|
288
229
|
else:
|
|
289
230
|
raise ValueError(f'Invalid split by newline: {field}')
|
|
290
231
|
if fields_to_assign_ids:
|
|
291
|
-
|
|
292
|
-
fields = fields_to_assign_ids.split(',')
|
|
293
|
-
for field in fields:
|
|
294
|
-
if '=' in field:
|
|
295
|
-
dst, src = field.split('=')
|
|
296
|
-
dict_assign_ids[dst] = src
|
|
297
|
-
else:
|
|
298
|
-
raise ValueError(f'Invalid id assignment: {field}')
|
|
232
|
+
setup_assign_ids(config, fields_to_assign_ids)
|
|
299
233
|
if output_file:
|
|
300
234
|
ext = os.path.splitext(output_file)[1]
|
|
301
235
|
if ext not in dict_savers:
|
|
@@ -330,8 +264,8 @@ def convert(
|
|
|
330
264
|
new_row = remap_columns(new_row, config.map)
|
|
331
265
|
if config.process.split_by_newline:
|
|
332
266
|
new_row = apply_fields_split_by_newline(new_row, config.process.split_by_newline)
|
|
333
|
-
if
|
|
334
|
-
new_row = assign_id(new_row,
|
|
267
|
+
if config.process.assign_ids:
|
|
268
|
+
new_row = assign_id(new_row, config.process.assign_ids, id_context_map)
|
|
335
269
|
if config.process.assign_formats:
|
|
336
270
|
new_row = map_formats(new_row, config.process.assign_formats)
|
|
337
271
|
if config.map:
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from collections import OrderedDict
|
|
8
|
+
from collections import defaultdict
|
|
9
|
+
from typing import Mapping
|
|
10
|
+
|
|
11
|
+
# 3-rd party modules
|
|
12
|
+
|
|
13
|
+
from icecream import ic
|
|
14
|
+
import numpy as np
|
|
15
|
+
import pandas as pd
|
|
16
|
+
|
|
17
|
+
# local
|
|
18
|
+
|
|
19
|
+
from ..config import (
|
|
20
|
+
AssignIdConfig,
|
|
21
|
+
Config,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from . search_column_value import search_column_value
|
|
25
|
+
from . set_field_value import set_field_value
|
|
26
|
+
|
|
27
|
+
type ContextColumnTuple = tuple[str]
|
|
28
|
+
type ContextValueTuple = tuple
|
|
29
|
+
type PrimaryColumnTuple = tuple[str]
|
|
30
|
+
type PrimaryValueTuple = tuple
|
|
31
|
+
|
|
32
|
+
@dataclasses.dataclass
|
|
33
|
+
class IdMap:
|
|
34
|
+
max_id: int = 0
|
|
35
|
+
dict_value_to_id: Mapping[PrimaryValueTuple, int] = \
|
|
36
|
+
dataclasses.field(default_factory=defaultdict)
|
|
37
|
+
dict_id_to_value: Mapping[int, PrimaryValueTuple] = \
|
|
38
|
+
dataclasses.field(default_factory=defaultdict)
|
|
39
|
+
|
|
40
|
+
type IdContextMap = Mapping[
|
|
41
|
+
(
|
|
42
|
+
ContextColumnTuple,
|
|
43
|
+
ContextValueTuple,
|
|
44
|
+
PrimaryColumnTuple,
|
|
45
|
+
),
|
|
46
|
+
IdMap
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
def create_id_context_map() -> IdContextMap:
|
|
50
|
+
return defaultdict(IdMap)
|
|
51
|
+
|
|
52
|
+
def assign_id(
|
|
53
|
+
row: OrderedDict,
|
|
54
|
+
dict_assignment: Mapping[str, AssignIdConfig],
|
|
55
|
+
id_context_map: IdContextMap,
|
|
56
|
+
):
|
|
57
|
+
new_row = OrderedDict(row)
|
|
58
|
+
for column, config in dict_assignment.items():
|
|
59
|
+
context_columns = []
|
|
60
|
+
context_values = []
|
|
61
|
+
if config.context:
|
|
62
|
+
for context_column in config.context:
|
|
63
|
+
value, found = search_column_value(new_row, context_column)
|
|
64
|
+
if not found:
|
|
65
|
+
raise KeyError(f'Column not found: {context_column}, existing columns: {new_row.keys()}')
|
|
66
|
+
context_columns.append(context_column)
|
|
67
|
+
context_values.append(value)
|
|
68
|
+
primary_columns = []
|
|
69
|
+
primary_values = []
|
|
70
|
+
for primary_column in config.primary:
|
|
71
|
+
value, found = search_column_value(new_row, primary_column)
|
|
72
|
+
if not found:
|
|
73
|
+
raise KeyError(f'Column not found: {primary_column}, existing columns: {new_row.keys()}')
|
|
74
|
+
primary_columns.append(primary_column)
|
|
75
|
+
primary_values.append(value)
|
|
76
|
+
context_key = (
|
|
77
|
+
tuple(context_columns),
|
|
78
|
+
tuple(context_values),
|
|
79
|
+
tuple(primary_columns),
|
|
80
|
+
)
|
|
81
|
+
primary_value = tuple(primary_values)
|
|
82
|
+
id_map = id_context_map[context_key]
|
|
83
|
+
if primary_value not in id_map.dict_value_to_id:
|
|
84
|
+
field_id = id_map.max_id + 1
|
|
85
|
+
id_map.max_id = field_id
|
|
86
|
+
id_map.dict_value_to_id[primary_value] = field_id
|
|
87
|
+
id_map.dict_id_to_value[field_id] = primary_value
|
|
88
|
+
else:
|
|
89
|
+
field_id = id_map.dict_value_to_id[primary_value]
|
|
90
|
+
set_field_value(new_row, f'__debug__.{column}', field_id)
|
|
91
|
+
return new_row
|
|
92
|
+
|
|
93
|
+
def setup_assign_ids(
|
|
94
|
+
config: Config,
|
|
95
|
+
fields_to_assign_ids: str,
|
|
96
|
+
):
|
|
97
|
+
if fields_to_assign_ids:
|
|
98
|
+
fields = fields_to_assign_ids.split(',')
|
|
99
|
+
context = []
|
|
100
|
+
for field in fields:
|
|
101
|
+
if '=' in field:
|
|
102
|
+
dst, src = field.split('=')
|
|
103
|
+
config.process.assign_ids[dst] = AssignIdConfig(
|
|
104
|
+
primary = [src],
|
|
105
|
+
context = context,
|
|
106
|
+
)
|
|
107
|
+
else:
|
|
108
|
+
raise ValueError(f'Invalid id assignment: {field}')
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Description: Get the value of a field in a dictionary.
|
|
2
|
+
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
|
|
5
|
+
def get_field_value(
|
|
6
|
+
data: OrderedDict,
|
|
7
|
+
field: str,
|
|
8
|
+
):
|
|
9
|
+
if field in data:
|
|
10
|
+
return data[field], True
|
|
11
|
+
if '.' in field:
|
|
12
|
+
field, rest = field.split('.', 1)
|
|
13
|
+
if field in data:
|
|
14
|
+
return get_field_value(data[field], rest)
|
|
15
|
+
return None, False
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'''
|
|
2
|
+
This function is used to search for a column value in a row. It will first search in the '__debug__' field, then in the '__debug__.__original__' field, and finally in the row itself. If the value is found, it will be set in the row and returned.
|
|
3
|
+
'''
|
|
4
|
+
|
|
5
|
+
from collections import OrderedDict
|
|
6
|
+
|
|
7
|
+
from . get_field_value import get_field_value
|
|
8
|
+
from . set_field_value import set_field_value
|
|
9
|
+
|
|
10
|
+
def search_column_value(
|
|
11
|
+
row: OrderedDict,
|
|
12
|
+
column: str,
|
|
13
|
+
):
|
|
14
|
+
if '__debug__' in row:
|
|
15
|
+
value, found = get_field_value(row['__debug__'], column)
|
|
16
|
+
if found:
|
|
17
|
+
return value, True
|
|
18
|
+
value, found = get_field_value(row['__debug__'], column)
|
|
19
|
+
original, found = get_field_value(row, '__debug__.__original__')
|
|
20
|
+
if found:
|
|
21
|
+
value, found = get_field_value(original, column)
|
|
22
|
+
if found:
|
|
23
|
+
return value, True
|
|
24
|
+
value, found = get_field_value(row, column)
|
|
25
|
+
if found:
|
|
26
|
+
set_field_value(row, column, value)
|
|
27
|
+
return value, True
|
|
28
|
+
return None, False
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Set the value of a field in a nested dictionary.
|
|
3
|
+
'''
|
|
4
|
+
|
|
5
|
+
from collections import OrderedDict
|
|
6
|
+
|
|
7
|
+
def set_field_value(
|
|
8
|
+
data: OrderedDict,
|
|
9
|
+
field: str,
|
|
10
|
+
value: any,
|
|
11
|
+
):
|
|
12
|
+
if '.' in field:
|
|
13
|
+
field, rest = field.split('.', 1)
|
|
14
|
+
if field not in data:
|
|
15
|
+
data[field] = OrderedDict()
|
|
16
|
+
set_field_value(data[field], rest, value)
|
|
17
|
+
else:
|
|
18
|
+
data[field] = value
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
from collections import OrderedDict
|
|
4
|
-
import dataclasses
|
|
5
|
-
from typing import Mapping
|
|
6
|
-
|
|
7
|
-
from icecream import ic
|
|
8
|
-
import yaml
|
|
9
|
-
|
|
10
|
-
type FlatFieldMap = Mapping[str, str]
|
|
11
|
-
type FieldMap = Mapping[str, str|FieldMap]
|
|
12
|
-
|
|
13
|
-
@dataclasses.dataclass
|
|
14
|
-
class ProcessConfig:
|
|
15
|
-
assign_constants: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
|
|
16
|
-
assign_formats: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
|
|
17
|
-
split_by_newline: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
|
|
18
|
-
|
|
19
|
-
def __setitem__(self, key, value):
|
|
20
|
-
setattr(self, key, value)
|
|
21
|
-
|
|
22
|
-
@dataclasses.dataclass
|
|
23
|
-
class Config:
|
|
24
|
-
map: FieldMap = dataclasses.field(default_factory=OrderedDict)
|
|
25
|
-
process: ProcessConfig = dataclasses.field(default_factory=ProcessConfig)
|
|
26
|
-
|
|
27
|
-
def flatten(
|
|
28
|
-
mapping: FieldMap,
|
|
29
|
-
parent_key: str = '',
|
|
30
|
-
new_mapping: FlatFieldMap | None = None,
|
|
31
|
-
) -> FlatFieldMap:
|
|
32
|
-
if new_mapping is None:
|
|
33
|
-
new_mapping = OrderedDict()
|
|
34
|
-
for key, mapped in mapping.items():
|
|
35
|
-
new_key = f'{parent_key}.{key}' if parent_key else key
|
|
36
|
-
if isinstance(mapped, Mapping):
|
|
37
|
-
flatten(mapped, new_key, new_mapping)
|
|
38
|
-
else:
|
|
39
|
-
new_mapping[new_key] = mapped
|
|
40
|
-
return new_mapping
|
|
41
|
-
|
|
42
|
-
def setup_config(
|
|
43
|
-
config_path: str | None = None,
|
|
44
|
-
):
|
|
45
|
-
config = Config()
|
|
46
|
-
if config_path:
|
|
47
|
-
if config_path.endswith('.yaml'):
|
|
48
|
-
yaml.add_constructor(
|
|
49
|
-
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
|
|
50
|
-
lambda loader, node: OrderedDict(loader.construct_pairs(node)),
|
|
51
|
-
)
|
|
52
|
-
with open(config_path, 'r') as f:
|
|
53
|
-
loaded = yaml.load(f, yaml.Loader)
|
|
54
|
-
else:
|
|
55
|
-
raise ValueError(
|
|
56
|
-
'Only YAML configuration files are supported.'
|
|
57
|
-
)
|
|
58
|
-
ic(loaded)
|
|
59
|
-
if 'map' in loaded:
|
|
60
|
-
config.map = flatten(loaded['map'])
|
|
61
|
-
dict_process = loaded.get('process')
|
|
62
|
-
if isinstance(dict_process, Mapping):
|
|
63
|
-
for process_key in [
|
|
64
|
-
'assign_constants',
|
|
65
|
-
'assign_formats',
|
|
66
|
-
'split_by_newline',
|
|
67
|
-
]:
|
|
68
|
-
dict_subprocess = dict_process.get(process_key)
|
|
69
|
-
if isinstance(dict_subprocess, Mapping):
|
|
70
|
-
config.process[process_key] = flatten(loaded['process'][process_key])
|
|
71
|
-
return config
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|