python-table-converter 0.2.9__tar.gz → 0.2.11__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 (16) hide show
  1. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/PKG-INFO +1 -1
  2. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/pyproject.toml +1 -1
  3. python_table_converter-0.2.11/table_converter/__init__.py +2 -0
  4. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/table_converter/commands/convert_tables.py +12 -0
  5. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/table_converter/core/config.py +57 -4
  6. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/table_converter/core/convert.py +79 -17
  7. python_table_converter-0.2.9/table_converter/__init__.py +0 -2
  8. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/LICENSE +0 -0
  9. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/README.md +0 -0
  10. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/table_converter/cli.py +0 -0
  11. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/table_converter/core/constants.py +0 -0
  12. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/table_converter/core/functions/assign_id.py +0 -0
  13. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/table_converter/core/functions/flatten.py +0 -0
  14. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/table_converter/core/functions/get_field_value.py +0 -0
  15. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/table_converter/core/functions/search_column_value.py +0 -0
  16. {python_table_converter-0.2.9 → python_table_converter-0.2.11}/table_converter/core/functions/set_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.9
3
+ Version: 0.2.11
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.9"
3
+ version = "0.2.11"
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.11"
2
+ __version_tuple__ = (0, 2, 11)
@@ -15,9 +15,11 @@ def run(
15
15
  config_path = args.config,
16
16
  assign_constants = args.assign_constants,
17
17
  assign_formats = args.assign_formats,
18
+ str_filters = args.filters,
18
19
  pickup_columns= args.pickup_columns,
19
20
  fields_to_split_by_newline = args.split_by_newline,
20
21
  fields_to_assign_ids = args.assign_ids,
22
+ str_omit_fields= args.omit_fields,
21
23
  output_debug = args.output_debug,
22
24
  )
23
25
 
@@ -66,6 +68,16 @@ def setup_parser(
66
68
  type=str,
67
69
  help='Field to assign formats',
68
70
  )
71
+ parser.add_argument(
72
+ '--filters', '--filter', '-f',
73
+ type=str,
74
+ help='Expression list to filter records',
75
+ )
76
+ parser.add_argument(
77
+ '--omit-fields', '--omit',
78
+ type=str,
79
+ help='Field to omit',
80
+ )
69
81
  parser.add_argument(
70
82
  '--output-debug',
71
83
  action='store_true',
@@ -2,7 +2,10 @@
2
2
 
3
3
  from collections import OrderedDict
4
4
  import dataclasses
5
- from typing import Mapping
5
+ from typing import (
6
+ Literal,
7
+ Mapping,
8
+ )
6
9
 
7
10
  from icecream import ic
8
11
  import yaml
@@ -18,13 +21,27 @@ class AssignIdConfig:
18
21
  primary: list[str]
19
22
  context: list[str] | None = None
20
23
 
24
+ @dataclasses.dataclass
25
+ class FilterConfig:
26
+ field: str
27
+ operator: Literal['==', '!=', '>', '>=', '<', '<=']
28
+ value: str
29
+
30
+ @dataclasses.dataclass
31
+ class SplitConfig:
32
+ field: str
33
+ delimiter: str
34
+
21
35
  @dataclasses.dataclass
22
36
  class ProcessConfig:
23
37
  assign_constants: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
24
38
  assign_formats: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
25
- #assign_ids: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
26
39
  assign_ids: Mapping[str, AssignIdConfig] = dataclasses.field(default_factory=OrderedDict)
27
- split_by_newline: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
40
+ #filter_eq: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
41
+ filter: list[FilterConfig] = dataclasses.field(default_factory=list)
42
+ omit_fields: list[str] = dataclasses.field(default_factory=list)
43
+ #split_by_newline: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
44
+ split: Mapping[str, SplitConfig] = dataclasses.field(default_factory=OrderedDict)
28
45
 
29
46
  def __setitem__(self, key, value):
30
47
  setattr(self, key, value)
@@ -65,12 +82,12 @@ def setup_process_config(
65
82
  for process_key in [
66
83
  'assign_constants',
67
84
  'assign_formats',
68
- 'split_by_newline',
69
85
  ]:
70
86
  dict_subprocess = dict_process.get(process_key)
71
87
  if isinstance(dict_subprocess, Mapping):
72
88
  config.process[process_key] = flatten(loaded['process'][process_key])
73
89
  setup_process_assign_ids_config(config, dict_process)
90
+ setup_process_split_config(config, dict_process)
74
91
 
75
92
  def setup_process_assign_ids_config(
76
93
  config: Config,
@@ -108,3 +125,39 @@ def setup_process_assign_ids_config(
108
125
  raise ValueError(
109
126
  f'Unsupported assign_ids value type: {type(value)}'
110
127
  )
128
+
129
+ def setup_process_split_config(
130
+ config: Config,
131
+ dict_process: Mapping,
132
+ ):
133
+ dict_subprocess = dict_process.get('split')
134
+ if isinstance(dict_subprocess, Mapping):
135
+ for key, value in dict_subprocess.items():
136
+ if isinstance(value, Mapping):
137
+ field = value.get('field')
138
+ if not field:
139
+ ic.enable()
140
+ ic(value)
141
+ ic(value.get('field'))
142
+ raise ValueError(
143
+ 'Field is required for split.'
144
+ )
145
+ delimiter = value.get('delimiter')
146
+ if not delimiter:
147
+ ic.enable()
148
+ ic(value)
149
+ ic(value.get('delimiter'))
150
+ raise ValueError(
151
+ 'Delimiter is required for split.'
152
+ )
153
+ config.process.split[key] = SplitConfig(
154
+ field = field,
155
+ delimiter = delimiter,
156
+ )
157
+ else:
158
+ ic.enable()
159
+ ic(value)
160
+ ic(type(value))
161
+ raise ValueError(
162
+ f'Unsupported assign_ids value type: {type(value)}'
163
+ )
@@ -14,7 +14,11 @@ import pandas as pd
14
14
 
15
15
  # local
16
16
 
17
- from . config import setup_config
17
+ from . config import (
18
+ FilterConfig,
19
+ SplitConfig,
20
+ setup_config,
21
+ )
18
22
  from . constants import (
19
23
  FILE_FIELD,
20
24
  INPUT_FIELD,
@@ -65,7 +69,7 @@ def load_json(
65
69
  data = json.load(f)
66
70
  if not isinstance(data, list):
67
71
  raise ValueError(f'Invalid JSON array data: {input_file}')
68
- ic(data[0])
72
+ #ic(data[0])
69
73
  rows = []
70
74
  for row in data:
71
75
  new_row = flatten(row)
@@ -103,9 +107,9 @@ def save_json(
103
107
  #)
104
108
  #ic(df.iloc[0])
105
109
  data = df.to_dict(orient='records')
106
- ic(data[0])
110
+ #ic(data[0])
107
111
  data = [nest(row) for row in data]
108
- ic(data[0])
112
+ #ic(data[0])
109
113
  with open(output_file, 'w') as f:
110
114
  json.dump(
111
115
  data,
@@ -190,27 +194,50 @@ def remap_columns(
190
194
  new_row[column] = row[column]
191
195
  return new_row
192
196
 
193
- def apply_fields_split_by_newline(
197
+ def split_fields(
194
198
  row: OrderedDict,
195
- dict_fields: OrderedDict,
199
+ dict_config: list[SplitConfig],
196
200
  ):
197
201
  new_row = OrderedDict(row)
198
- for column in dict_fields:
199
- value, found = search_column_value(row, dict_fields[column])
202
+ for dst, config in dict_config.items():
203
+ value, found = search_column_value(row, config.field)
200
204
  if found:
201
205
  if isinstance(value, str):
202
- new_value = value.split('\n')
203
- new_row[f'{STAGING_FIELD}.{column}'] = new_value
206
+ new_value = value.split(config.delimiter)
207
+ new_value = list(filter(None, new_value))
208
+ if not new_value:
209
+ ic(dst, config, value)
210
+ new_row[f'{STAGING_FIELD}.{dst}'] = new_value
204
211
  else:
205
- new_row[f'{STAGING_FIELD}.{column}'] = value
212
+ new_row[f'{STAGING_FIELD}.{dst}'] = value
206
213
  return new_row
207
214
 
215
+ def filter_row(
216
+ row: OrderedDict,
217
+ list_filters: list[FilterConfig],
218
+ ):
219
+ for config in list_filters:
220
+ value, found = search_column_value(row, config.field)
221
+ if config.operator == '==':
222
+ if not found:
223
+ return False
224
+ if str(value) != str(config.value):
225
+ return False
226
+ elif config.operator == '!=':
227
+ if str(value) == str(config.value):
228
+ return False
229
+ else:
230
+ raise ValueError(f'Unsupported operator: {config.operator}')
231
+ return True
232
+
208
233
  def convert(
209
234
  input_files: list[str],
210
235
  output_file: str | None = None,
211
236
  config_path: str | None = None,
212
237
  assign_constants: str | None = None,
213
238
  assign_formats: str | None = None,
239
+ str_filters: str | None = None,
240
+ str_omit_fields: str | None = None,
214
241
  pickup_columns: str | None = None,
215
242
  fields_to_split_by_newline: str | None = None,
216
243
  fields_to_assign_ids: str | None = None,
@@ -252,9 +279,36 @@ def convert(
252
279
  for field in fields:
253
280
  if '=' in field:
254
281
  dst, src = field.split('=')
255
- config.process.split_by_newline[dst] = src
282
+ #config.process.split_by_newline[dst] = src
283
+ config.process.split[dst] = SplitConfig(
284
+ field = src,
285
+ delimiter = '\n',
286
+ )
256
287
  else:
257
288
  raise ValueError(f'Invalid split by newline: {field}')
289
+ if str_filters:
290
+ fields = str_filters.split(',')
291
+ for field in fields:
292
+ if '==' in field:
293
+ column, value = field.split('==')
294
+ config.process.filter.append(FilterConfig(
295
+ field = column,
296
+ operator = '==',
297
+ value = value,
298
+ ))
299
+ elif '!=' in field:
300
+ column, value = field.split('!=')
301
+ config.process.filter.append(FilterConfig(
302
+ field = column,
303
+ operator = '!=',
304
+ value = value,
305
+ ))
306
+ else:
307
+ raise ValueError(f'Invalid filter eq: {field}')
308
+ if str_omit_fields:
309
+ fields = str_omit_fields.split(',')
310
+ for field in fields:
311
+ config.process.omit_fields.append(field)
258
312
  if fields_to_assign_ids:
259
313
  setup_assign_ids(config, fields_to_assign_ids)
260
314
  if output_file:
@@ -293,24 +347,32 @@ def convert(
293
347
  new_flat_row = map_constants(new_flat_row, config.process.assign_constants)
294
348
  if config.map:
295
349
  new_flat_row = remap_columns(new_flat_row, config.map)
296
- if config.process.split_by_newline:
297
- new_flat_row = apply_fields_split_by_newline(new_flat_row, config.process.split_by_newline)
350
+ if config.process.split:
351
+ new_flat_row = split_fields(new_flat_row, config.process.split)
298
352
  if config.process.assign_ids:
299
353
  new_flat_row = assign_id(new_flat_row, config.process.assign_ids, id_context_map)
300
354
  if config.process.assign_formats:
301
355
  new_flat_row = map_formats(new_flat_row, config.process.assign_formats)
302
356
  if config.map:
303
357
  new_flat_row = remap_columns(new_flat_row, config.map)
358
+ if config.process.filter:
359
+ if not filter_row(new_flat_row, config.process.filter):
360
+ continue
361
+ if config.process.omit_fields:
362
+ for field in config.process.omit_fields:
363
+ new_flat_row.pop(field, None)
304
364
  if not output_debug:
305
- new_flat_row.pop(STAGING_FIELD, None)
365
+ for key in list(new_flat_row.keys()):
366
+ if key.startswith(STAGING_FIELD):
367
+ new_flat_row.pop(key)
306
368
  new_flat_rows.append(new_flat_row)
307
369
  new_df = pd.DataFrame(new_flat_rows)
308
370
  df_list.append(new_df)
309
371
  all_df = pd.concat(df_list)
310
372
  #ic(all_df)
311
373
  ic(len(all_df))
312
- ic(all_df.columns)
313
- ic(all_df.iloc[0])
374
+ #ic(all_df.columns)
375
+ #ic(all_df.iloc[0])
314
376
  if output_file:
315
377
  ic('Saing to: ', output_file)
316
378
  saver(all_df, output_file)
@@ -1,2 +0,0 @@
1
- __version__ = "0.2.9"
2
- __version_tuple__ = (0, 2, 9)