python-table-converter 0.2.8__tar.gz → 0.2.9__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.
Files changed (17) hide show
  1. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/PKG-INFO +1 -1
  2. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/pyproject.toml +1 -1
  3. python_table_converter-0.2.9/table_converter/__init__.py +2 -0
  4. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/table_converter/core/config.py +5 -18
  5. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/table_converter/core/convert.py +67 -51
  6. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/table_converter/core/functions/assign_id.py +6 -2
  7. python_table_converter-0.2.9/table_converter/core/functions/flatten.py +24 -0
  8. python_table_converter-0.2.9/table_converter/core/functions/search_column_value.py +25 -0
  9. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/table_converter/core/functions/set_field_value.py +1 -0
  10. python_table_converter-0.2.8/table_converter/__init__.py +0 -2
  11. python_table_converter-0.2.8/table_converter/core/functions/search_column_value.py +0 -30
  12. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/LICENSE +0 -0
  13. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/README.md +0 -0
  14. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/table_converter/cli.py +0 -0
  15. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/table_converter/commands/convert_tables.py +0 -0
  16. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/table_converter/core/constants.py +0 -0
  17. {python_table_converter-0.2.8 → python_table_converter-0.2.9}/table_converter/core/functions/get_field_value.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-table-converter
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: A table data converter
5
5
  Home-page: https://github.com/akivajp/python-table-converter
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-table-converter"
3
- version = "0.2.8"
3
+ version = "0.2.9"
4
4
  description = "A table data converter"
5
5
  authors = ["Akiva Miura <akiva.miura@gmail.com>"]
6
6
  license = "MIT"
@@ -0,0 +1,2 @@
1
+ __version__ = "0.2.9"
2
+ __version_tuple__ = (0, 2, 9)
@@ -7,13 +7,15 @@ from typing import Mapping
7
7
  from icecream import ic
8
8
  import yaml
9
9
 
10
- type FlatFieldMap = Mapping[str, str]
11
- type FieldMap = Mapping[str, str|FieldMap]
10
+ from . functions.flatten import (
11
+ FieldMap,
12
+ FlatFieldMap,
13
+ flatten,
14
+ )
12
15
 
13
16
  @dataclasses.dataclass
14
17
  class AssignIdConfig:
15
18
  primary: list[str]
16
- #given: list[str] | None = None
17
19
  context: list[str] | None = None
18
20
 
19
21
  @dataclasses.dataclass
@@ -32,21 +34,6 @@ class Config:
32
34
  map: FieldMap = dataclasses.field(default_factory=OrderedDict)
33
35
  process: ProcessConfig = dataclasses.field(default_factory=ProcessConfig)
34
36
 
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
37
  def setup_config(
51
38
  config_path: str | None = None,
52
39
  ):
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  import json
4
+ import math
4
5
  import os
5
6
 
6
7
  from collections import OrderedDict
@@ -24,7 +25,11 @@ from . functions.assign_id import (
24
25
  create_id_context_map,
25
26
  setup_assign_ids,
26
27
  )
28
+ from . functions.flatten import (
29
+ flatten,
30
+ )
27
31
  from . functions.get_field_value import get_field_value
32
+ from . functions.search_column_value import search_column_value
28
33
  from . functions.set_field_value import set_field_value
29
34
 
30
35
  dict_loaders: dict[str, callable] = {}
@@ -58,9 +63,31 @@ def load_json(
58
63
  ):
59
64
  with open(input_file, 'r') as f:
60
65
  data = json.load(f)
61
- df = pd.DataFrame(data)
66
+ if not isinstance(data, list):
67
+ raise ValueError(f'Invalid JSON array data: {input_file}')
68
+ ic(data[0])
69
+ rows = []
70
+ for row in data:
71
+ new_row = flatten(row)
72
+ rows.append(new_row)
73
+ df = pd.DataFrame(rows)
62
74
  return df
63
75
 
76
+ def nest(
77
+ row: OrderedDict,
78
+ remove_nan: bool = True,
79
+ ):
80
+ new_row = OrderedDict()
81
+ for key, value in row.items():
82
+ if isinstance(value, OrderedDict):
83
+ value = nest(value)
84
+ if isinstance(value, float):
85
+ if math.isnan(value):
86
+ if remove_nan:
87
+ continue
88
+ set_field_value(new_row, key, value)
89
+ return new_row
90
+
64
91
  @register_saver('.json')
65
92
  def save_json(
66
93
  df: pd.DataFrame,
@@ -76,6 +103,9 @@ def save_json(
76
103
  #)
77
104
  #ic(df.iloc[0])
78
105
  data = df.to_dict(orient='records')
106
+ ic(data[0])
107
+ data = [nest(row) for row in data]
108
+ ic(data[0])
79
109
  with open(output_file, 'w') as f:
80
110
  json.dump(
81
111
  data,
@@ -106,34 +136,13 @@ def save_jsonl(
106
136
  )
107
137
  f.write('\n')
108
138
 
109
- def search_column_value(
110
- row: OrderedDict,
111
- column: str,
112
- ):
113
- if STAGING_FIELD in row:
114
- value, found = get_field_value(row[STAGING_FIELD], column)
115
- if found:
116
- return value, True
117
- value, found = get_field_value(row[STAGING_FIELD], column)
118
- original, found = get_field_value(row, f'{STAGING_FIELD}.{INPUT_FIELD}')
119
- if found:
120
- value, found = get_field_value(original, column)
121
- if found:
122
- return value, True
123
- value, found = get_field_value(row, column)
124
- if found:
125
- set_field_value(row, column, value)
126
- return value, True
127
- return None, False
128
-
129
139
  def map_constants(
130
140
  row: OrderedDict,
131
141
  dict_constants: OrderedDict,
132
142
  ):
133
143
  new_row = OrderedDict(row)
134
144
  for column in dict_constants.keys():
135
- #set_field_value(new_row, column, dict_constants[column])
136
- set_field_value(new_row, f'{STAGING_FIELD}.{column}', dict_constants[column])
145
+ new_row[f'{STAGING_FIELD}.{column}'] = dict_constants[column]
137
146
  return new_row
138
147
 
139
148
  def map_formats(
@@ -144,7 +153,11 @@ def map_formats(
144
153
  for column in dict_formats.keys():
145
154
  template = dict_formats[column]
146
155
  params = {}
147
- params.update(row[STAGING_FIELD])
156
+ for key, value in row.items():
157
+ prefix = f'{STAGING_FIELD}.'
158
+ if key.startswith(prefix):
159
+ rest = key[len(prefix):]
160
+ params[rest] = value
148
161
  params.update(row)
149
162
  formatted = None
150
163
  while formatted is None:
@@ -158,7 +171,7 @@ def map_formats(
158
171
  params[key] = f'__{key}__undefined__'
159
172
  except:
160
173
  raise
161
- set_field_value(new_row, f'{STAGING_FIELD}.{column}', formatted)
174
+ new_row[f'{STAGING_FIELD}.{column}'] = formatted
162
175
  return new_row
163
176
 
164
177
  def remap_columns(
@@ -169,11 +182,12 @@ def remap_columns(
169
182
  for column in dict_remap.keys():
170
183
  value, found = search_column_value(row, dict_remap[column])
171
184
  if found:
172
- set_field_value(new_row, column, value)
185
+ new_row[column] = value
173
186
  for column in row.keys():
174
- if column == STAGING_FIELD:
175
- # NOTE: Ignore debug fields
176
- set_field_value(new_row, column, row[column])
187
+ prefix = f'{STAGING_FIELD}.'
188
+ if column.startswith(prefix):
189
+ # NOTE: Leave staging fields as is
190
+ new_row[column] = row[column]
177
191
  return new_row
178
192
 
179
193
  def apply_fields_split_by_newline(
@@ -183,13 +197,12 @@ def apply_fields_split_by_newline(
183
197
  new_row = OrderedDict(row)
184
198
  for column in dict_fields:
185
199
  value, found = search_column_value(row, dict_fields[column])
186
- #ic(value, found)
187
200
  if found:
188
201
  if isinstance(value, str):
189
202
  new_value = value.split('\n')
190
- set_field_value(new_row, f'{STAGING_FIELD}.{column}', new_value)
203
+ new_row[f'{STAGING_FIELD}.{column}'] = new_value
191
204
  else:
192
- set_field_value(new_row, f'{STAGING_FIELD}.{column}', value)
205
+ new_row[f'{STAGING_FIELD}.{column}'] = value
193
206
  return new_row
194
207
 
195
208
  def convert(
@@ -263,32 +276,35 @@ def convert(
263
276
  # NOTE: NaN を None に変換しておかないと厄介
264
277
  df = df.replace([np.nan], [None])
265
278
  #ic(df)
266
- ic(len(df))
267
- ic(df.columns)
268
- ic(df.iloc[0])
269
- new_rows = []
270
- for index, row in df.iterrows():
271
- orig = OrderedDict(row)
272
- new_row = OrderedDict(row)
273
- if STAGING_FIELD not in new_row:
274
- set_field_value(new_row, f'{STAGING_FIELD}.{INPUT_FIELD}', orig)
275
- set_field_value(new_row, f'{STAGING_FIELD}.{FILE_FIELD}', input_file)
279
+ #ic(len(df))
280
+ #ic(df.columns)
281
+ #ic(df.iloc[0])
282
+ #new_rows = []
283
+ new_flat_rows = []
284
+ for index, flat_row in df.iterrows():
285
+ orig = OrderedDict(flat_row)
286
+ new_flat_row = OrderedDict(flat_row)
287
+ new_nested_row = nest(new_flat_row)
288
+ if STAGING_FIELD not in new_nested_row:
289
+ new_flat_row[f'{STAGING_FIELD}.{FILE_FIELD}'] = input_file
290
+ for key, value in orig.items():
291
+ new_flat_row[f'{STAGING_FIELD}.{INPUT_FIELD}.{key}'] = value
276
292
  if config.process.assign_constants:
277
- new_row = map_constants(new_row, config.process.assign_constants)
293
+ new_flat_row = map_constants(new_flat_row, config.process.assign_constants)
278
294
  if config.map:
279
- new_row = remap_columns(new_row, config.map)
295
+ new_flat_row = remap_columns(new_flat_row, config.map)
280
296
  if config.process.split_by_newline:
281
- new_row = apply_fields_split_by_newline(new_row, config.process.split_by_newline)
297
+ new_flat_row = apply_fields_split_by_newline(new_flat_row, config.process.split_by_newline)
282
298
  if config.process.assign_ids:
283
- new_row = assign_id(new_row, config.process.assign_ids, id_context_map)
299
+ new_flat_row = assign_id(new_flat_row, config.process.assign_ids, id_context_map)
284
300
  if config.process.assign_formats:
285
- new_row = map_formats(new_row, config.process.assign_formats)
301
+ new_flat_row = map_formats(new_flat_row, config.process.assign_formats)
286
302
  if config.map:
287
- new_row = remap_columns(new_row, config.map)
303
+ new_flat_row = remap_columns(new_flat_row, config.map)
288
304
  if not output_debug:
289
- new_row.pop(STAGING_FIELD, None)
290
- new_rows.append(new_row)
291
- new_df = pd.DataFrame(new_rows)
305
+ new_flat_row.pop(STAGING_FIELD, None)
306
+ new_flat_rows.append(new_flat_row)
307
+ new_df = pd.DataFrame(new_flat_rows)
292
308
  df_list.append(new_df)
293
309
  all_df = pd.concat(df_list)
294
310
  #ic(all_df)
@@ -16,7 +16,11 @@ import pandas as pd
16
16
 
17
17
  # local
18
18
 
19
- from ..config import (
19
+ from .. constants import (
20
+ STAGING_FIELD,
21
+ )
22
+
23
+ from .. config import (
20
24
  AssignIdConfig,
21
25
  Config,
22
26
  )
@@ -87,7 +91,7 @@ def assign_id(
87
91
  id_map.dict_id_to_value[field_id] = primary_value
88
92
  else:
89
93
  field_id = id_map.dict_value_to_id[primary_value]
90
- set_field_value(new_row, f'__debug__.{column}', field_id)
94
+ new_row[f'{STAGING_FIELD}.{column}'] = field_id
91
95
  return new_row
92
96
 
93
97
  def setup_assign_ids(
@@ -0,0 +1,24 @@
1
+ '''
2
+ This module contains the function to flatten a nested dictionary.
3
+ '''
4
+
5
+ from collections import OrderedDict
6
+ from typing import Mapping
7
+
8
+ type FlatFieldMap = Mapping[str]
9
+ type FieldMap = Mapping[str, str|FieldMap]
10
+
11
+ def flatten(
12
+ mapping: FieldMap,
13
+ parent_key: str = '',
14
+ new_mapping: FlatFieldMap | None = None,
15
+ ) -> FlatFieldMap:
16
+ if new_mapping is None:
17
+ new_mapping = OrderedDict()
18
+ for key, mapped in mapping.items():
19
+ new_key = f'{parent_key}.{key}' if parent_key else key
20
+ if isinstance(mapped, Mapping):
21
+ flatten(mapped, new_key, new_mapping)
22
+ else:
23
+ new_mapping[new_key] = mapped
24
+ return new_mapping
@@ -0,0 +1,25 @@
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 .. constants import (
6
+ INPUT_FIELD,
7
+ STAGING_FIELD,
8
+ )
9
+
10
+ from collections import OrderedDict
11
+
12
+ def search_column_value(
13
+ row: OrderedDict,
14
+ column: str,
15
+ ):
16
+ if f'{STAGING_FIELD}.{column}' in row:
17
+ value = row[f'{STAGING_FIELD}.{column}']
18
+ return value, True
19
+ if f'{STAGING_FIELD}.{INPUT_FIELD}.{column}' in row:
20
+ value = row[f'{STAGING_FIELD}.{INPUT_FIELD}.{column}']
21
+ return value, True
22
+ if column in row:
23
+ value = row[column]
24
+ return value, True
25
+ return None, False
@@ -3,6 +3,7 @@ Set the value of a field in a nested dictionary.
3
3
  '''
4
4
 
5
5
  from collections import OrderedDict
6
+ from icecream import ic
6
7
 
7
8
  def set_field_value(
8
9
  data: OrderedDict,
@@ -1,2 +0,0 @@
1
- __version__ = "0.2.8"
2
- __version_tuple__ = (0, 2, 8)
@@ -1,30 +0,0 @@
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 .. constants import STAGING_FIELD
6
-
7
- from collections import OrderedDict
8
-
9
- from . get_field_value import get_field_value
10
- from . set_field_value import set_field_value
11
-
12
- def search_column_value(
13
- row: OrderedDict,
14
- column: str,
15
- ):
16
- if STAGING_FIELD in row:
17
- value, found = get_field_value(row[STAGING_FIELD], column)
18
- if found:
19
- return value, True
20
- value, found = get_field_value(row[STAGING_FIELD], column)
21
- original, found = get_field_value(row, f'{STAGING_FIELD}.__original__')
22
- if found:
23
- value, found = get_field_value(original, column)
24
- if found:
25
- return value, True
26
- value, found = get_field_value(row, column)
27
- if found:
28
- set_field_value(row, column, value)
29
- return value, True
30
- return None, False