python-table-processor 0.3.1__py3-none-any.whl → 0.3.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-table-processor
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: A table data processor
5
5
  Home-page: https://github.com/akivajp/python-table-processor
6
6
  License: MIT
@@ -1,11 +1,11 @@
1
- table_processor/__init__.py,sha256=7U6Yq5pgarhomICnrlEYAI32ycMhvYb4mYoUd4axAyU,52
1
+ table_processor/__init__.py,sha256=IqYTIOR96kwEp7nfLi1h2e7pZiFKmLonFJ-wwSegFkw,52
2
2
  table_processor/cli.py,sha256=uluf_VsBzq3Ldxh3ePGseSrv8--lI7huu-6RjDaHPPg,2170
3
3
  table_processor/commands/convert_tables.py,sha256=j25KL0zRl5ikrBk73jAkKn4rPmDq7SecChZxecDpILQ,2123
4
4
  table_processor/commands/merge_tables.py,sha256=Uu-hjfPh69Of0_OZrY8sY0oscpLSdK4jwJ_t1qgfPMg,1485
5
- table_processor/core/actions.py,sha256=rXdXXo8AXUaLnrzDp8vRduU0XxIOD7PQdkjHiJzOzq8,19702
6
- table_processor/core/config.py,sha256=irJxJBhBQNz5cp9XlMjVpZ47hxclG6pkTphK-SCrZQ0,11727
5
+ table_processor/core/actions.py,sha256=WLlq-G8Pb9xjsLpXK1QVCwhK20ijz2oIbTFibihdFTE,21557
6
+ table_processor/core/config.py,sha256=Z1s2r3y4oQXdbDCwIY_hYzoq6VRv7Sb3oUlfBCu13Lc,11646
7
7
  table_processor/core/constants.py,sha256=w-1TxtpXywb6Qh8M4YWuzcCHUvCjy5zJYxaXC3RQS6A,158
8
- table_processor/core/convert.py,sha256=2R9zf0SzRZEpNEd51eym10mJ3kb5vLSnsY81z4dDXCA,11566
8
+ table_processor/core/convert.py,sha256=cibzqJ5hHsfX_7qUz4kE2Gi-WH4UMqecBl3kSb4IVsY,11140
9
9
  table_processor/core/functions/assign_id.py,sha256=dA-wgZA7E01gbx8qGvo1PeMd3aq9PhMdyITzr3BKXIE,4204
10
10
  table_processor/core/functions/flatten_row.py,sha256=2l-s4YXgBM58IthpfVzd7L4EGUCekSi7ss5CaM_3MUU,686
11
11
  table_processor/core/functions/get_nested_field_value.py,sha256=vF4pH6nxR3-2bDfAvrMfHcPFNiS4MnGkXL8FdcScdIw,685
@@ -15,9 +15,9 @@ table_processor/core/functions/set_flat_field_value.py,sha256=7-BgD2yEUGyBaFaIJ1
15
15
  table_processor/core/functions/set_nested_field_value.py,sha256=csO0v_nW94q-M9bNL91xR-TLHPXDDxnLK8gN-0LLd6k,595
16
16
  table_processor/core/functions/set_row_value.py,sha256=wlF_nVGZY74XCzd6pBJJyti62m6y0s1kc5Q6uq9jn8o,641
17
17
  table_processor/core/merge.py,sha256=Yc5OV9n1xV9QtgY4srl6Susd5cOKbuYseEtYuBampDw,4672
18
- table_processor/core/types.py,sha256=vqm7Jyktrcd3qvfJspu8421MwsXI-jxnCeXAbmpTDHw,2498
19
- python_table_processor-0.3.1.dist-info/LICENSE,sha256=1_Gn0I1neLPxDLfLiHEyxjDg-pbAra1p2iHEqutGS_c,1068
20
- python_table_processor-0.3.1.dist-info/METADATA,sha256=nAAAO4VF74FJv3Qd-Jd1lNRTQVvEOKDcZWu-13C04_g,1098
21
- python_table_processor-0.3.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
22
- python_table_processor-0.3.1.dist-info/entry_points.txt,sha256=lq97F6m51yZ93qmVIqkUHJfbILZuYLxrMWXSqrP4JpM,118
23
- python_table_processor-0.3.1.dist-info/RECORD,,
18
+ table_processor/core/types.py,sha256=qASw6zDJXFpaswKjhSQ39wcTH8BcCmp7xKW_hgP-RRY,2665
19
+ python_table_processor-0.3.3.dist-info/LICENSE,sha256=1_Gn0I1neLPxDLfLiHEyxjDg-pbAra1p2iHEqutGS_c,1068
20
+ python_table_processor-0.3.3.dist-info/METADATA,sha256=mvhOnT4vISkKBt5HCEecLCTIRrwrWivJyn63II1w5Jk,1098
21
+ python_table_processor-0.3.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
22
+ python_table_processor-0.3.3.dist-info/entry_points.txt,sha256=lq97F6m51yZ93qmVIqkUHJfbILZuYLxrMWXSqrP4JpM,118
23
+ python_table_processor-0.3.3.dist-info/RECORD,,
@@ -1,2 +1,2 @@
1
- __version__ = "0.3.1"
2
- __version_tuple__ = (0, 3, 1)
1
+ __version__ = "0.3.3"
2
+ __version_tuple__ = (0, 3, 3)
@@ -28,6 +28,7 @@ from . types import (
28
28
  AssignConstantConfig,
29
29
  AssignFormatConfig,
30
30
  AssignIdConfig,
31
+ AssignLengthConfig,
31
32
  FilterConfig,
32
33
  GlobalStatus,
33
34
  JoinConfig,
@@ -140,6 +141,12 @@ def setup_actions_with_args(
140
141
  reverse = reverse,
141
142
  ))
142
143
  continue
144
+ if action_name == 'assign-length':
145
+ config.actions.append(AssignLengthConfig(
146
+ target = target,
147
+ source = source,
148
+ ))
149
+ continue
143
150
  if action_name == 'filter-empty':
144
151
  config.actions.append(FilterConfig(
145
152
  field = target,
@@ -170,15 +177,26 @@ def setup_actions_with_args(
170
177
  if action_name == 'parse':
171
178
  as_type = options.get('as', 'literal')
172
179
  required = options.get('required', False)
173
- if as_type not in ['json', 'literal']:
180
+ if as_type in ['boolean']:
181
+ as_type = 'bool'
182
+ if as_type not in ['bool', 'json', 'literal']:
174
183
  raise ValueError(
175
184
  f'Unsupported as type: {as_type}'
176
185
  )
186
+ assign_default = False
187
+ default_value = None
188
+ if 'default' in options:
189
+ assign_default = True
190
+ default_value = options['default']
191
+ if default_value in ['None', 'none', 'Null', 'null']:
192
+ default_value = None
177
193
  config.actions.append(ParseConfig(
178
194
  target = target,
179
195
  source = source,
180
196
  as_type = as_type,
181
197
  required = required,
198
+ assign_default = assign_default,
199
+ default_value = default_value,
182
200
  ))
183
201
  continue
184
202
  if action_name == 'parse-json':
@@ -303,6 +321,8 @@ def do_action(
303
321
  return assign_format(row, action)
304
322
  if isinstance(action, AssignIdConfig):
305
323
  return assign_id(status.id_context_map, row, action)
324
+ if isinstance(action, AssignLengthConfig):
325
+ return assign_length(row, action)
306
326
  if isinstance(action, FilterConfig):
307
327
  if filter_row(row, action):
308
328
  return row
@@ -590,27 +610,48 @@ def parse(
590
610
  f'Required field not found, field: {config.source}'
591
611
  )
592
612
  if found:
593
- if type(value) == str:
594
- if config.as_type == 'literal':
595
- try:
613
+ if config.as_type == 'literal':
614
+ try:
615
+ if type(value) is str:
596
616
  parsed = ast.literal_eval(value)
597
- except:
598
- raise ValueError(
599
- f'Failed to parse literal: {value}'
600
- )
601
- elif config.as_type == 'json':
602
- try:
617
+ else:
618
+ parsed = value
619
+ except:
620
+ raise ValueError(
621
+ f'Failed to parse literal: {value}'
622
+ )
623
+ elif config.as_type == 'json':
624
+ try:
625
+ if type(value) is str:
603
626
  parsed = json.loads(value)
604
- except:
627
+ else:
628
+ parsed = value
629
+ except:
630
+ raise ValueError(
631
+ f'Failed to parse JSON: {value}'
632
+ )
633
+ elif config.as_type == 'bool':
634
+ if config.assign_default and value in [None, '']:
635
+ value = config.default_value
636
+ if type(value) is bool:
637
+ parsed = value
638
+ elif type(value) is str:
639
+ if value.lower() in ['true', 'yes', 'on', '1']:
640
+ parsed = True
641
+ elif value.lower() in ['false', 'no', 'off', '0']:
642
+ parsed = False
643
+ else:
605
644
  raise ValueError(
606
- f'Failed to parse JSON: {value}'
645
+ f'Failed to parse bool: {value}'
607
646
  )
608
647
  else:
609
648
  raise ValueError(
610
- f'Unsupported as type: {config.as_type}'
649
+ f'Failed to parse bool: {value}'
611
650
  )
612
651
  else:
613
- parsed = value
652
+ raise ValueError(
653
+ f'Unsupported as type: {config.as_type}'
654
+ )
614
655
  set_row_staging_value(row, config.target, parsed)
615
656
  return row
616
657
 
@@ -635,3 +676,12 @@ def push_field(
635
676
  set_row_staging_value(row, config.target, array)
636
677
  array.append(source_value)
637
678
  return row
679
+
680
+ def assign_length(
681
+ row: Row,
682
+ config: AssignLengthConfig,
683
+ ):
684
+ value, found = search_column_value(row.nested, config.source)
685
+ if found:
686
+ set_row_staging_value(row, config.target, len(value))
687
+ return row
@@ -34,7 +34,6 @@ class AssignArrayConfig:
34
34
  @dataclasses.dataclass
35
35
  class ProcessConfig:
36
36
  assign_array: Mapping[str, list[AssignArrayConfig]] = dataclasses.field(default_factory=OrderedDict)
37
- assign_length: FlatFieldMap = dataclasses.field(default_factory=OrderedDict)
38
37
 
39
38
  def __setitem__(self, key, value):
40
39
  setattr(self, key, value)
@@ -263,17 +263,6 @@ def search_column_value_from_nested(
263
263
  return None, False
264
264
 
265
265
 
266
- def assign_length(
267
- row: OrderedDict,
268
- dict_fields: OrderedDict,
269
- ):
270
- new_row = OrderedDict(row)
271
- for key, field in dict_fields.items():
272
- value, found = search_column_value(row, field)
273
- if found:
274
- new_row[f'{STAGING_FIELD}.{key}'] = len(value)
275
- return new_row
276
-
277
266
  def convert(
278
267
  input_files: list[str],
279
268
  output_file: str | None = None,
@@ -348,8 +337,6 @@ def convert(
348
337
  set_row_staging_value(row, INPUT_FIELD, orig_row.nested)
349
338
  if config.process.assign_array:
350
339
  row.flat= assign_array(row.flat, config.process.assign_array)
351
- if config.process.assign_length:
352
- row.flat = assign_length(row.flat, config.process.assign_length)
353
340
  if config.actions:
354
341
  try:
355
342
  new_row = do_actions(global_status, row, config.actions)
@@ -46,6 +46,11 @@ class AssignIdConfig:
46
46
  context: list[str] | None = None
47
47
  reverse: bool = False
48
48
 
49
+ @dataclasses.dataclass
50
+ class AssignLengthConfig:
51
+ target: str
52
+ source: str
53
+
49
54
  @dataclasses.dataclass
50
55
  class FilterConfig:
51
56
  field: str
@@ -69,8 +74,12 @@ class OmitConfig:
69
74
  class ParseConfig:
70
75
  target: str
71
76
  source: str
72
- as_type: Literal['json', 'literal']
77
+ as_type: Literal[
78
+ 'bool', 'json', 'literal'
79
+ ]
73
80
  required: bool = False
81
+ assign_default: bool = False
82
+ default_value: Any = None
74
83
 
75
84
  @dataclasses.dataclass
76
85
  class PickConfig: