excel-list-transform 1.1__tar.gz → 1.3__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 (48) hide show
  1. {excel_list_transform-1.1 → excel_list_transform-1.3}/PKG-INFO +111 -15
  2. {excel_list_transform-1.1 → excel_list_transform-1.3}/README.md +8 -4
  3. excel_list_transform-1.1/excel_list_transform.egg-info/PKG-INFO → excel_list_transform-1.3/README_pypi.md +99 -37
  4. excel_list_transform-1.1/README_pypi.md → excel_list_transform-1.3/excel_list_transform.egg-info/PKG-INFO +133 -9
  5. {excel_list_transform-1.1 → excel_list_transform-1.3}/excel_list_transform.egg-info/SOURCES.txt +3 -0
  6. excel_list_transform-1.3/excel_list_transform.egg-info/requires.txt +10 -0
  7. {excel_list_transform-1.1 → excel_list_transform-1.3}/pyproject.toml +2 -2
  8. {excel_list_transform-1.1 → excel_list_transform-1.3}/setup.py +12 -7
  9. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/config_enums.py +17 -0
  10. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/config_excel_list_transform.py +46 -24
  11. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/config_read_old.py +4 -0
  12. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/config_xls_list_transf_name.py +9 -4
  13. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/config_xls_list_transf_num.py +8 -4
  14. excel_list_transform-1.3/src/excel_list_transform/edit_cfg.py +150 -0
  15. excel_list_transform-1.3/src/excel_list_transform/edit_descriptions.py +336 -0
  16. excel_list_transform-1.3/src/excel_list_transform/file_extension.py +28 -0
  17. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/generate_cfg.py +18 -16
  18. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/generate_txt.py +52 -4
  19. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/handle_tableio.py +10 -2
  20. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/num_named_conversion.py +13 -0
  21. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/rewrite_value.py +8 -6
  22. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/row_split_merge.py +64 -80
  23. excel_list_transform-1.3/src/excel_list_transform/split_parts.py +56 -0
  24. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/transform_cmd.py +40 -1
  25. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/transform_func_common.py +32 -19
  26. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/transform_func_named.py +31 -7
  27. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/transform_func_num.py +1 -3
  28. excel_list_transform-1.3/src/excel_list_transform/version_information.py +52 -0
  29. excel_list_transform-1.1/excel_list_transform.egg-info/requires.txt +0 -5
  30. excel_list_transform-1.1/src/excel_list_transform/file_extension.py +0 -30
  31. excel_list_transform-1.1/src/excel_list_transform/version_information.py +0 -32
  32. {excel_list_transform-1.1 → excel_list_transform-1.3}/LICENSE.txt +0 -0
  33. {excel_list_transform-1.1 → excel_list_transform-1.3}/excel_list_transform.egg-info/dependency_links.txt +0 -0
  34. {excel_list_transform-1.1 → excel_list_transform-1.3}/excel_list_transform.egg-info/top_level.txt +0 -0
  35. {excel_list_transform-1.1 → excel_list_transform-1.3}/setup.cfg +0 -0
  36. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/__init__.py +0 -0
  37. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/__main__.py +0 -0
  38. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/check_indata_common.py +0 -0
  39. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/commontypes.py +0 -0
  40. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/config_match.py +0 -0
  41. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/file_must_exist.py +0 -0
  42. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/handle_empty_column.py +0 -0
  43. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/migrate_cfg.py +0 -0
  44. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/migrate_cfg_warn_hook.py +0 -0
  45. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/py.typed +0 -0
  46. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/recode.py +0 -0
  47. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/str_to_enum.py +0 -0
  48. {excel_list_transform-1.1 → excel_list_transform-1.3}/src/excel_list_transform/transform_func.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: excel-list-transform
3
- Version: 1.1
3
+ Version: 1.3
4
4
  Summary: Transform table data with configurable row and column changes.
5
5
  Author: Tom Björkholm
6
6
  Author-email: Tom Björkholm <klausuler_linnet0q@icloud.com>
@@ -9,6 +9,7 @@ Project-URL: Source code, https://github.com/tom-bjorkholm/excel-list-transform
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: Programming Language :: Python :: 3.13
11
11
  Classifier: Programming Language :: Python :: 3.14
12
+ Classifier: Programming Language :: Python :: 3.15
12
13
  Classifier: Operating System :: OS Independent
13
14
  Classifier: Intended Audience :: Other Audience
14
15
  Classifier: Topic :: Office/Business
@@ -16,13 +17,18 @@ Classifier: Typing :: Typed
16
17
  Requires-Python: >=3.13
17
18
  Description-Content-Type: text/markdown
18
19
  License-File: LICENSE.txt
19
- Requires-Dist: tableio-cfg-json>=0.8
20
- Requires-Dist: tableio>=1.1
21
- Requires-Dist: config-as-json>=1.4
22
- Requires-Dist: versionreporter>=0.4
23
- Requires-Dist: argcomplete>=3.7.0
20
+ Requires-Dist: tableio-cfg-json>=2.0
21
+ Requires-Dist: tableio>=1.3
22
+ Requires-Dist: config-as-json>=1.8
23
+ Requires-Dist: versionreporter>=0.5
24
+ Requires-Dist: argcomplete>=3.7.2
25
+ Requires-Dist: edit-cfg-json>=1.0.0
26
+ Requires-Dist: edit-cfg-json-tk>=1.0.0
27
+ Provides-Extra: textual
28
+ Requires-Dist: edit-cfg-json-textual>=1.0.0; extra == "textual"
24
29
  Dynamic: author
25
30
  Dynamic: license-file
31
+ Dynamic: provides-extra
26
32
  Dynamic: requires-dist
27
33
  Dynamic: requires-python
28
34
 
@@ -63,7 +69,8 @@ This small python application:
63
69
 
64
70
  How this is done is governed by a configuration file. The application can
65
71
  create a number of example configuration files with accompanying description
66
- text files.
72
+ text files, and can open a configuration file in a configuration editor that
73
+ explains every setting.
67
74
 
68
75
  ## Installing it
69
76
 
@@ -84,6 +91,19 @@ pip3 install --upgrade excel-list-transform
84
91
  pip install --upgrade excel-list-transform
85
92
  ````
86
93
 
94
+ ### Installing the terminal configuration editor (optional)
95
+
96
+ The "editcfg" sub-command opens the configuration editor in a window when
97
+ there is a display. To also be able to edit in the terminal (for instance
98
+ over a remote shell without a display), install the optional extra
99
+ "textual":
100
+
101
+ ````sh
102
+ pip3 install --upgrade "excel-list-transform[textual]"
103
+ ````
104
+
105
+ (On Microsoft Windows use `pip` instead of `pip3`.)
106
+
87
107
  ## Running the application
88
108
 
89
109
  ### Running the application on mac and Linux
@@ -97,6 +117,8 @@ python3 -m excel_list_transform cfg-example -k forms_to_rrs -r by_name -o exampl
97
117
  python3 -m excel_list_transform transform -c example.cfg -i input.xlsx -o output.xlsx
98
118
  python3 -m excel_list_transform migrate-cfg --help
99
119
  python3 -m excel_list_transform migrate-cfg -i old.cfg -o new.cfg
120
+ python3 -m excel_list_transform editcfg --help
121
+ python3 -m excel_list_transform editcfg -i example.cfg
100
122
  ````
101
123
 
102
124
  ### Running the application on Microsoft Windows
@@ -110,6 +132,8 @@ python -m excel_list_transform cfg-example -k forms_to_rrs -r by_name -o example
110
132
  python -m excel_list_transform transform -c example.cfg -i input.xlsx -o output.xlsx
111
133
  python -m excel_list_transform migrate-cfg --help
112
134
  python -m excel_list_transform migrate-cfg -i old.cfg -o new.cfg
135
+ python -m excel_list_transform editcfg --help
136
+ python -m excel_list_transform editcfg -i example.cfg
113
137
  ````
114
138
 
115
139
  ## Suggested way to get started
@@ -120,6 +144,8 @@ python -m excel_list_transform migrate-cfg -i old.cfg -o new.cfg
120
144
  description (.txt) files.
121
145
  3. Find an example that is close to what you want to achieve.
122
146
  4. Modify that configuration file to achieve what you want to achieve.
147
+ Use the "editcfg" sub-command to modify it in a configuration editor that
148
+ explains every setting (or modify it in a text editor).
123
149
  5. Use the "transform" sub-command to read your data and output it transformed
124
150
  or reorganized according to your modified configuration file.
125
151
  6. Read the produced output. If necessary go back to step 4 and adjust how the
@@ -139,6 +165,23 @@ text file describing it.
139
165
  Read the text file describing the configuration file while looking at the
140
166
  configuration file to understand the syntax and the possible options.
141
167
 
168
+ ### Editing a configuration file
169
+
170
+ The "editcfg" sub-command opens a configuration file in a configuration
171
+ editor. The editor shows an explanation of every setting, checks the values
172
+ before saving, and keeps a backup (.bak) of the file it overwrites. It opens
173
+ in a window when there is a display, otherwise in the terminal (if the
174
+ optional extra "textual" is installed, see above). Use the "--ui" option to
175
+ choose the editor yourself, and the "-o" option to save to another file than
176
+ the one you opened.
177
+
178
+ "column_ref" cannot be changed in the editor, as the rest of the file is
179
+ written for it. Generate a new example with the other "-r" value instead.
180
+
181
+ There is a separate user guide for the editor opened by the "editcfg"
182
+ sub-command. See
183
+ [https://github.com/tom-bjorkholm/edit-cfg-json/blob/master/doc/end_users_guide.md](https://github.com/tom-bjorkholm/edit-cfg-json/blob/master/doc/end_users_guide.md)
184
+
142
185
  ## Performance
143
186
 
144
187
  This application is written for the moderate amounts of data when
@@ -270,7 +313,8 @@ referenced by number.
270
313
  The first operation is to split rows based on column values.
271
314
  This operation is configured using the **"s01_split_rows"** record,
272
315
  that has an array of splits to be done. Each row split has the
273
- following keys: **"column"**, **"separators"** and **"not_separators"**.
316
+ following keys: **"column"**, **"separators"**, **"not_separators"**
317
+ and **"empty_parts"**.
274
318
 
275
319
  The **"column"** keyword is used to identify the column that is
276
320
  split into several rows. This is a column number in the case of
@@ -286,11 +330,36 @@ these strings are present in the identified column it is seen
286
330
  as the separator between the parts of the column value that go
287
331
  into different rows.
288
332
 
333
+ Separators must not be empty strings. If more than one
334
+ separator matches at the same position, the longest one is used.
335
+
289
336
  **"not_separators"** take as argument a list of strings. These strings
290
337
  are not regarded as separators even if they include the strings
291
338
  of one or more separator. (For instance ";" could be a separator,
292
339
  but using **"not_separators"** the string "\\;" could be seen as not
293
340
  a separator.)
341
+ The column value is scanned from the start. At each position a
342
+ not-separator takes precedence over a separator, so a separator
343
+ that is part of a not-separator never splits the value.
344
+
345
+ **"empty_parts"** decides what happens to empty parts. A part is the
346
+ text between two separators, or between a separator and the start
347
+ or end of the value. A part is empty if it is "" or only whitespace.
348
+ Empty parts come from a separator at the start or end of the value,
349
+ or from two adjacent separators. **"empty_parts"** can have the values:
350
+
351
+ - *"KEEP_ALL"*: keep all empty parts. They give rows where the column
352
+ is empty. "a,,b," split at "," gives "a", "", "b" and "".
353
+ - *"DROP_ALL"*: drop all empty parts. "a,,b," gives "a" and "b".
354
+ - *"DROP_TRAILING"*: drop only the empty parts at the end. "a,,b,"
355
+ gives "a", "" and "b", and "a,b,," gives "a" and "b". This is
356
+ useful when a separator is written after every element of a list,
357
+ also after the last one.
358
+
359
+ If all parts are dropped (for instance the value "," with *"DROP_ALL"*),
360
+ the row is kept once with the value "" in the column. An empty cell
361
+ is not split. Configuration files without **"empty_parts"** (from older
362
+ versions) get *"KEEP_ALL"*, which is how older versions worked.
294
363
 
295
364
  ### "s02_merge_rows"
296
365
 
@@ -309,6 +378,7 @@ For each column that has the same value for all rows merged, that
309
378
  value will be in the merged row. When rows being merged have different
310
379
  values for a column, the set of unique values from different rows
311
380
  will form the value for that column in the merged row.
381
+ Empty values are left out.
312
382
 
313
383
  The **"separator"** keyword is used to specify the string that is
314
384
  concatenated between values for one column from different rows
@@ -346,10 +416,10 @@ the least confusion is to split columns to the right before
346
416
  columns to the left. Named references also helps to avoid
347
417
  confusion.)
348
418
 
349
- Each split has the following keys: **"column"**, **"separator"** and
350
- **"where"**. In the case of number column references there is
351
- also the key **"store_single"**. In the case of named column references
352
- there is instead the key **"right_name"**.
419
+ Each split has the following keys: **"column"**, **"separator"**,
420
+ **"where"** and **"end_separators"**. In the case of number column
421
+ references there is also the key **"store_single"**. In the case of
422
+ named column references there is instead the key **"right_name"**.
353
423
 
354
424
  **"column"** takes as argument the column to be split. This is a
355
425
  column number in the case of *"BY_NUMBER"*, and a column name/title
@@ -358,6 +428,7 @@ in the case of *"BY_NAME"*.
358
428
  **"separator"** is a string of characters that indicate the position
359
429
  where the column shall be split. (For instance a single space
360
430
  if splitting between two words.)
431
+ The separator must not be an empty string.
361
432
 
362
433
  **"where"** can either have the value *"RIGHTMOST"* or the value
363
434
  *"LEFTMOST"*. This is used if the separator string is present
@@ -365,6 +436,25 @@ more than once in the column value to split. The split is then
365
436
  done at the leftmost or rightmost occurrence according to the
366
437
  value of **"where"**.
367
438
 
439
+ **"end_separators"** decides what happens to separators at the start
440
+ or end of the value, before the split is done. Without removing them,
441
+ "a,b," split at the rightmost "," gives "a,b" and "", and split at
442
+ the leftmost "," gives "a" and "b,". **"end_separators"** can have the
443
+ values:
444
+
445
+ - *"KEEP"*: keep the value as it is.
446
+ - *"STRIP_LEADING"*: remove separators at the start of the value.
447
+ - *"STRIP_TRAILING"*: remove separators at the end of the value.
448
+ - *"STRIP_BOTH_ENDS"*: remove separators at both the start and the end
449
+ of the value.
450
+
451
+ All consecutive separators at a stripped end are removed, together
452
+ with any whitespace between them. For instance "a,b, ," with
453
+ *"STRIP_TRAILING"* becomes "a,b" before it is split. A value that
454
+ consists only of separators and whitespace becomes "".
455
+ Configuration files without **"end_separators"** (from older versions)
456
+ get *"KEEP"*, which is how older versions worked.
457
+
368
458
  **"right_name"** is only used if column references are *"BY_NAME"*.
369
459
  After the split the left column uses the original column name,
370
460
  and **"right_name"** is used as the name of the new right column.
@@ -395,6 +485,7 @@ column references are column numbers.
395
485
 
396
486
  **"separator"** is a string of characters that is inserted between
397
487
  the column values being merged.
488
+ Empty values are left out.
398
489
 
399
490
  ### "s06_place_columns_first"
400
491
 
@@ -414,6 +505,8 @@ column number in the case of *"BY_NUMBER"*, and a column name/title
414
505
  in the case of *"BY_NAME"*.
415
506
 
416
507
  **"name"** is the new name/title of the column identified by **"column"**.
508
+ In the case of *"BY_NAME"* the renames are done in the listed order,
509
+ and a rename must not give a column the name of an existing column.
417
510
 
418
511
  ### "s08_insert_columns"
419
512
 
@@ -486,6 +579,8 @@ The value of the **"s10_column_order"** key is a list of column names.
486
579
  The columns will be output in this order.
487
580
  Columns not mentioned in **"s10_column_order"** will not be output,
488
581
  and will thus be removed.
582
+ Each name in **"s10_column_order"** must be the name of an existing
583
+ column (as named after all other steps).
489
584
  (For *"BY_NUMBER"* see **"s04_remove_columns"** and **"s06_place_columns_first"**.)
490
585
 
491
586
  ## Utility for recoding text files
@@ -510,9 +605,10 @@ Source code and tests are available at [https://github.com/tom-bjorkholm/excel-l
510
605
 
511
606
  ## Test summary
512
607
 
513
- - Test result: 1368 passed, 1 warning in 64s (0:01:04)
608
+ - Test result: 1693 passed in 88s (0:01:28)
514
609
  - No flake8 warnings.
515
610
  - No mypy errors found.
611
+ - No pylint warnings.
516
612
  - No python layout warnings.
517
- - Built version(s): 1.1
518
- - Build and test using Python 3.14.6
613
+ - Built version(s): 1.3
614
+ - Build and test using Python 3.15.2
@@ -45,7 +45,10 @@ This small python application:
45
45
  an ODS spreadsheet file, a comma separated values (CSV) file, or
46
46
  any of a number of other file formats.
47
47
 
48
- How this is done is governed by a configuration file. The application can create a number of example configuration files with accompanying description text files.
48
+ How this is done is governed by a configuration file. The application can
49
+ create a number of example configuration files with accompanying description
50
+ text files, and can open a configuration file in a configuration editor
51
+ that explains every setting.
49
52
 
50
53
  ## Cloning
51
54
 
@@ -107,9 +110,10 @@ the built and installed application in the virtual environment `./venv`.
107
110
 
108
111
  ## Test summary
109
112
 
110
- - Test result: 1368 passed, 1 warning in 64s (0:01:04)
113
+ - Test result: 1693 passed in 88s (0:01:28)
111
114
  - No flake8 warnings.
112
115
  - No mypy errors found.
116
+ - No pylint warnings.
113
117
  - No python layout warnings.
114
- - Built version(s): 1.1
115
- - Build and test using Python 3.14.6
118
+ - Built version(s): 1.3
119
+ - Build and test using Python 3.15.2
@@ -1,31 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: excel-list-transform
3
- Version: 1.1
4
- Summary: Transform table data with configurable row and column changes.
5
- Author: Tom Björkholm
6
- Author-email: Tom Björkholm <klausuler_linnet0q@icloud.com>
7
- License-Expression: MIT
8
- Project-URL: Source code, https://github.com/tom-bjorkholm/excel-list-transform
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.13
11
- Classifier: Programming Language :: Python :: 3.14
12
- Classifier: Operating System :: OS Independent
13
- Classifier: Intended Audience :: Other Audience
14
- Classifier: Topic :: Office/Business
15
- Classifier: Typing :: Typed
16
- Requires-Python: >=3.13
17
- Description-Content-Type: text/markdown
18
- License-File: LICENSE.txt
19
- Requires-Dist: tableio-cfg-json>=0.8
20
- Requires-Dist: tableio>=1.1
21
- Requires-Dist: config-as-json>=1.4
22
- Requires-Dist: versionreporter>=0.4
23
- Requires-Dist: argcomplete>=3.7.0
24
- Dynamic: author
25
- Dynamic: license-file
26
- Dynamic: requires-dist
27
- Dynamic: requires-python
28
-
29
1
  # excel-list-transform
30
2
 
31
3
  ## Background
@@ -63,7 +35,8 @@ This small python application:
63
35
 
64
36
  How this is done is governed by a configuration file. The application can
65
37
  create a number of example configuration files with accompanying description
66
- text files.
38
+ text files, and can open a configuration file in a configuration editor that
39
+ explains every setting.
67
40
 
68
41
  ## Installing it
69
42
 
@@ -84,6 +57,19 @@ pip3 install --upgrade excel-list-transform
84
57
  pip install --upgrade excel-list-transform
85
58
  ````
86
59
 
60
+ ### Installing the terminal configuration editor (optional)
61
+
62
+ The "editcfg" sub-command opens the configuration editor in a window when
63
+ there is a display. To also be able to edit in the terminal (for instance
64
+ over a remote shell without a display), install the optional extra
65
+ "textual":
66
+
67
+ ````sh
68
+ pip3 install --upgrade "excel-list-transform[textual]"
69
+ ````
70
+
71
+ (On Microsoft Windows use `pip` instead of `pip3`.)
72
+
87
73
  ## Running the application
88
74
 
89
75
  ### Running the application on mac and Linux
@@ -97,6 +83,8 @@ python3 -m excel_list_transform cfg-example -k forms_to_rrs -r by_name -o exampl
97
83
  python3 -m excel_list_transform transform -c example.cfg -i input.xlsx -o output.xlsx
98
84
  python3 -m excel_list_transform migrate-cfg --help
99
85
  python3 -m excel_list_transform migrate-cfg -i old.cfg -o new.cfg
86
+ python3 -m excel_list_transform editcfg --help
87
+ python3 -m excel_list_transform editcfg -i example.cfg
100
88
  ````
101
89
 
102
90
  ### Running the application on Microsoft Windows
@@ -110,6 +98,8 @@ python -m excel_list_transform cfg-example -k forms_to_rrs -r by_name -o example
110
98
  python -m excel_list_transform transform -c example.cfg -i input.xlsx -o output.xlsx
111
99
  python -m excel_list_transform migrate-cfg --help
112
100
  python -m excel_list_transform migrate-cfg -i old.cfg -o new.cfg
101
+ python -m excel_list_transform editcfg --help
102
+ python -m excel_list_transform editcfg -i example.cfg
113
103
  ````
114
104
 
115
105
  ## Suggested way to get started
@@ -120,6 +110,8 @@ python -m excel_list_transform migrate-cfg -i old.cfg -o new.cfg
120
110
  description (.txt) files.
121
111
  3. Find an example that is close to what you want to achieve.
122
112
  4. Modify that configuration file to achieve what you want to achieve.
113
+ Use the "editcfg" sub-command to modify it in a configuration editor that
114
+ explains every setting (or modify it in a text editor).
123
115
  5. Use the "transform" sub-command to read your data and output it transformed
124
116
  or reorganized according to your modified configuration file.
125
117
  6. Read the produced output. If necessary go back to step 4 and adjust how the
@@ -139,6 +131,23 @@ text file describing it.
139
131
  Read the text file describing the configuration file while looking at the
140
132
  configuration file to understand the syntax and the possible options.
141
133
 
134
+ ### Editing a configuration file
135
+
136
+ The "editcfg" sub-command opens a configuration file in a configuration
137
+ editor. The editor shows an explanation of every setting, checks the values
138
+ before saving, and keeps a backup (.bak) of the file it overwrites. It opens
139
+ in a window when there is a display, otherwise in the terminal (if the
140
+ optional extra "textual" is installed, see above). Use the "--ui" option to
141
+ choose the editor yourself, and the "-o" option to save to another file than
142
+ the one you opened.
143
+
144
+ "column_ref" cannot be changed in the editor, as the rest of the file is
145
+ written for it. Generate a new example with the other "-r" value instead.
146
+
147
+ There is a separate user guide for the editor opened by the "editcfg"
148
+ sub-command. See
149
+ [https://github.com/tom-bjorkholm/edit-cfg-json/blob/master/doc/end_users_guide.md](https://github.com/tom-bjorkholm/edit-cfg-json/blob/master/doc/end_users_guide.md)
150
+
142
151
  ## Performance
143
152
 
144
153
  This application is written for the moderate amounts of data when
@@ -270,7 +279,8 @@ referenced by number.
270
279
  The first operation is to split rows based on column values.
271
280
  This operation is configured using the **"s01_split_rows"** record,
272
281
  that has an array of splits to be done. Each row split has the
273
- following keys: **"column"**, **"separators"** and **"not_separators"**.
282
+ following keys: **"column"**, **"separators"**, **"not_separators"**
283
+ and **"empty_parts"**.
274
284
 
275
285
  The **"column"** keyword is used to identify the column that is
276
286
  split into several rows. This is a column number in the case of
@@ -286,11 +296,36 @@ these strings are present in the identified column it is seen
286
296
  as the separator between the parts of the column value that go
287
297
  into different rows.
288
298
 
299
+ Separators must not be empty strings. If more than one
300
+ separator matches at the same position, the longest one is used.
301
+
289
302
  **"not_separators"** take as argument a list of strings. These strings
290
303
  are not regarded as separators even if they include the strings
291
304
  of one or more separator. (For instance ";" could be a separator,
292
305
  but using **"not_separators"** the string "\\;" could be seen as not
293
306
  a separator.)
307
+ The column value is scanned from the start. At each position a
308
+ not-separator takes precedence over a separator, so a separator
309
+ that is part of a not-separator never splits the value.
310
+
311
+ **"empty_parts"** decides what happens to empty parts. A part is the
312
+ text between two separators, or between a separator and the start
313
+ or end of the value. A part is empty if it is "" or only whitespace.
314
+ Empty parts come from a separator at the start or end of the value,
315
+ or from two adjacent separators. **"empty_parts"** can have the values:
316
+
317
+ - *"KEEP_ALL"*: keep all empty parts. They give rows where the column
318
+ is empty. "a,,b," split at "," gives "a", "", "b" and "".
319
+ - *"DROP_ALL"*: drop all empty parts. "a,,b," gives "a" and "b".
320
+ - *"DROP_TRAILING"*: drop only the empty parts at the end. "a,,b,"
321
+ gives "a", "" and "b", and "a,b,," gives "a" and "b". This is
322
+ useful when a separator is written after every element of a list,
323
+ also after the last one.
324
+
325
+ If all parts are dropped (for instance the value "," with *"DROP_ALL"*),
326
+ the row is kept once with the value "" in the column. An empty cell
327
+ is not split. Configuration files without **"empty_parts"** (from older
328
+ versions) get *"KEEP_ALL"*, which is how older versions worked.
294
329
 
295
330
  ### "s02_merge_rows"
296
331
 
@@ -309,6 +344,7 @@ For each column that has the same value for all rows merged, that
309
344
  value will be in the merged row. When rows being merged have different
310
345
  values for a column, the set of unique values from different rows
311
346
  will form the value for that column in the merged row.
347
+ Empty values are left out.
312
348
 
313
349
  The **"separator"** keyword is used to specify the string that is
314
350
  concatenated between values for one column from different rows
@@ -346,10 +382,10 @@ the least confusion is to split columns to the right before
346
382
  columns to the left. Named references also helps to avoid
347
383
  confusion.)
348
384
 
349
- Each split has the following keys: **"column"**, **"separator"** and
350
- **"where"**. In the case of number column references there is
351
- also the key **"store_single"**. In the case of named column references
352
- there is instead the key **"right_name"**.
385
+ Each split has the following keys: **"column"**, **"separator"**,
386
+ **"where"** and **"end_separators"**. In the case of number column
387
+ references there is also the key **"store_single"**. In the case of
388
+ named column references there is instead the key **"right_name"**.
353
389
 
354
390
  **"column"** takes as argument the column to be split. This is a
355
391
  column number in the case of *"BY_NUMBER"*, and a column name/title
@@ -358,6 +394,7 @@ in the case of *"BY_NAME"*.
358
394
  **"separator"** is a string of characters that indicate the position
359
395
  where the column shall be split. (For instance a single space
360
396
  if splitting between two words.)
397
+ The separator must not be an empty string.
361
398
 
362
399
  **"where"** can either have the value *"RIGHTMOST"* or the value
363
400
  *"LEFTMOST"*. This is used if the separator string is present
@@ -365,6 +402,25 @@ more than once in the column value to split. The split is then
365
402
  done at the leftmost or rightmost occurrence according to the
366
403
  value of **"where"**.
367
404
 
405
+ **"end_separators"** decides what happens to separators at the start
406
+ or end of the value, before the split is done. Without removing them,
407
+ "a,b," split at the rightmost "," gives "a,b" and "", and split at
408
+ the leftmost "," gives "a" and "b,". **"end_separators"** can have the
409
+ values:
410
+
411
+ - *"KEEP"*: keep the value as it is.
412
+ - *"STRIP_LEADING"*: remove separators at the start of the value.
413
+ - *"STRIP_TRAILING"*: remove separators at the end of the value.
414
+ - *"STRIP_BOTH_ENDS"*: remove separators at both the start and the end
415
+ of the value.
416
+
417
+ All consecutive separators at a stripped end are removed, together
418
+ with any whitespace between them. For instance "a,b, ," with
419
+ *"STRIP_TRAILING"* becomes "a,b" before it is split. A value that
420
+ consists only of separators and whitespace becomes "".
421
+ Configuration files without **"end_separators"** (from older versions)
422
+ get *"KEEP"*, which is how older versions worked.
423
+
368
424
  **"right_name"** is only used if column references are *"BY_NAME"*.
369
425
  After the split the left column uses the original column name,
370
426
  and **"right_name"** is used as the name of the new right column.
@@ -395,6 +451,7 @@ column references are column numbers.
395
451
 
396
452
  **"separator"** is a string of characters that is inserted between
397
453
  the column values being merged.
454
+ Empty values are left out.
398
455
 
399
456
  ### "s06_place_columns_first"
400
457
 
@@ -414,6 +471,8 @@ column number in the case of *"BY_NUMBER"*, and a column name/title
414
471
  in the case of *"BY_NAME"*.
415
472
 
416
473
  **"name"** is the new name/title of the column identified by **"column"**.
474
+ In the case of *"BY_NAME"* the renames are done in the listed order,
475
+ and a rename must not give a column the name of an existing column.
417
476
 
418
477
  ### "s08_insert_columns"
419
478
 
@@ -486,6 +545,8 @@ The value of the **"s10_column_order"** key is a list of column names.
486
545
  The columns will be output in this order.
487
546
  Columns not mentioned in **"s10_column_order"** will not be output,
488
547
  and will thus be removed.
548
+ Each name in **"s10_column_order"** must be the name of an existing
549
+ column (as named after all other steps).
489
550
  (For *"BY_NUMBER"* see **"s04_remove_columns"** and **"s06_place_columns_first"**.)
490
551
 
491
552
  ## Utility for recoding text files
@@ -510,9 +571,10 @@ Source code and tests are available at [https://github.com/tom-bjorkholm/excel-l
510
571
 
511
572
  ## Test summary
512
573
 
513
- - Test result: 1368 passed, 1 warning in 64s (0:01:04)
574
+ - Test result: 1693 passed in 88s (0:01:28)
514
575
  - No flake8 warnings.
515
576
  - No mypy errors found.
577
+ - No pylint warnings.
516
578
  - No python layout warnings.
517
- - Built version(s): 1.1
518
- - Build and test using Python 3.14.6
579
+ - Built version(s): 1.3
580
+ - Build and test using Python 3.15.2