flexablelib 2.0.0__tar.gz → 2.0.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 (42) hide show
  1. {flexablelib-2.0.0 → flexablelib-2.0.3}/CHANGELOG.md +80 -61
  2. {flexablelib-2.0.0/flexablelib.egg-info → flexablelib-2.0.3}/PKG-INFO +11 -24
  3. {flexablelib-2.0.0 → flexablelib-2.0.3}/README.md +8 -21
  4. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/cells.py +3 -2
  5. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/columns.py +17 -0
  6. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/merges.py +26 -9
  7. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/readers.py +37 -6
  8. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/table.py +17 -3
  9. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/writers.py +22 -0
  10. {flexablelib-2.0.0 → flexablelib-2.0.3/flexablelib.egg-info}/PKG-INFO +11 -24
  11. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib.egg-info/SOURCES.txt +1 -0
  12. {flexablelib-2.0.0 → flexablelib-2.0.3}/package.json +5 -5
  13. {flexablelib-2.0.0 → flexablelib-2.0.3}/setup.py +2 -2
  14. flexablelib-2.0.3/tests/test_excel.py +110 -0
  15. {flexablelib-2.0.0 → flexablelib-2.0.3}/tests/test_features.py +40 -0
  16. {flexablelib-2.0.0 → flexablelib-2.0.3}/tests/test_merges.py +59 -0
  17. {flexablelib-2.0.0 → flexablelib-2.0.3}/LICENSE +0 -0
  18. {flexablelib-2.0.0 → flexablelib-2.0.3}/MANIFEST.in +0 -0
  19. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/__init__.py +0 -0
  20. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/_speedups.c +0 -0
  21. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/_width_tables.h +0 -0
  22. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/colors.py +0 -0
  23. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/fast.py +0 -0
  24. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/options.py +0 -0
  25. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/style_compositions.py +0 -0
  26. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/table_strings.py +0 -0
  27. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/text_width.py +0 -0
  28. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib/utils.py +0 -0
  29. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib.egg-info/dependency_links.txt +0 -0
  30. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib.egg-info/requires.txt +0 -0
  31. {flexablelib-2.0.0 → flexablelib-2.0.3}/flexablelib.egg-info/top_level.txt +0 -0
  32. {flexablelib-2.0.0 → flexablelib-2.0.3}/setup.cfg +0 -0
  33. {flexablelib-2.0.0 → flexablelib-2.0.3}/tests/test_cells.py +0 -0
  34. {flexablelib-2.0.0 → flexablelib-2.0.3}/tests/test_columns.py +0 -0
  35. {flexablelib-2.0.0 → flexablelib-2.0.3}/tests/test_issues.py +0 -0
  36. {flexablelib-2.0.0 → flexablelib-2.0.3}/tests/test_readme_examples.py +0 -0
  37. {flexablelib-2.0.0 → flexablelib-2.0.3}/tests/test_styles.py +0 -0
  38. {flexablelib-2.0.0 → flexablelib-2.0.3}/tests/test_text_width.py +0 -0
  39. {flexablelib-2.0.0 → flexablelib-2.0.3}/tests/test_two_pass_measurement.py +0 -0
  40. {flexablelib-2.0.0 → flexablelib-2.0.3}/tests/test_upstream_issues.py +0 -0
  41. {flexablelib-2.0.0 → flexablelib-2.0.3}/tools/benchmark.py +0 -0
  42. {flexablelib-2.0.0 → flexablelib-2.0.3}/tools/generate_width_tables.py +0 -0
@@ -2,7 +2,26 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
- ## [2.0.0](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.4.1...v2.0.0) (2026-10-28)
5
+ ## [2.0.3](https://github.com/Opus-Perpetuus/flexablelib/compare/v2.0.2...v2.0.3) (2026-10-28)
6
+
7
+ ### Features
8
+
9
+ * ``to_excel`` / ``from_excel`` preserve merged cell ranges (openpyxl)
10
+
11
+ ## [2.0.2](https://github.com/Opus-Perpetuus/flexablelib/compare/v2.0.1...v2.0.2) (2026-10-28)
12
+
13
+ ### Bug Fixes
14
+
15
+ * redraw vertical-merge vertices as edges/tees instead of leftover corners
16
+
17
+ ## [2.0.1](https://github.com/Opus-Perpetuus/flexablelib/compare/v2.0.0...v2.0.1) (2026-10-28)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * `missing_val` is now an alias of `missing_value` (docs and constructor kwarg name no longer silently no-op)
23
+
24
+ ## [2.0.0](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.4.1...v2.0.0) (2026-10-28)
6
25
 
7
26
 
8
27
  ### ⚠ BREAKING CHANGES
@@ -19,7 +38,7 @@ All notable changes to this project will be documented in this file. See [standa
19
38
 
20
39
  * colour merge tests pin `use_colors=True` so CI without a TTY still asserts ANSI codes
21
40
 
22
- ## [1.4.1](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.4.0...v1.4.1) (2026-08-03)
41
+ ## [1.4.1](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.4.0...v1.4.1) (2026-08-03)
23
42
 
24
43
 
25
44
  ### Bug Fixes
@@ -27,7 +46,7 @@ All notable changes to this project will be documented in this file. See [standa
27
46
  * `column_max_width` now wraps or trims cell content to the cap (was only
28
47
  changing the measured width number, so long cells still overflowed)
29
48
 
30
- ## [1.4.0](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.3.0...v1.4.0) (2026-08-03)
49
+ ## [1.4.0](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.3.0...v1.4.0) (2026-08-03)
31
50
 
32
51
 
33
52
  ### Features
@@ -45,9 +64,9 @@ All notable changes to this project will be documented in this file. See [standa
45
64
 
46
65
  ### Bug Fixes
47
66
 
48
- * float columns keep decimal alignment when the table is shrunk ([#23](https://github.com/Opus-Perpetuus/prettyTables/issues/23))
49
- * alignment options are actually applied; `bool_align` no longer wrote the float slot ([#4](https://github.com/Opus-Perpetuus/prettyTables/issues/4))
50
- * empty rows and columns share one emptiness criterion ([#9](https://github.com/Opus-Perpetuus/prettyTables/issues/9))
67
+ * float columns keep decimal alignment when the table is shrunk ([#23](https://github.com/Opus-Perpetuus/flexablelib/issues/23))
68
+ * alignment options are actually applied; `bool_align` no longer wrote the float slot ([#4](https://github.com/Opus-Perpetuus/flexablelib/issues/4))
69
+ * empty rows and columns share one emptiness criterion ([#9](https://github.com/Opus-Perpetuus/flexablelib/issues/9))
51
70
  * column named `"i"` no longer collides with the index column
52
71
  * exponential numbers align with the float column
53
72
  * tabs, emoji VS16, empty header-only tables, markdown alignment colons, and other upstream regressions
@@ -60,117 +79,117 @@ All notable changes to this project will be documented in this file. See [standa
60
79
  * `docs/ISSUES.md` maps every tracker issue to its fix and tests
61
80
  * README Known Issues and ARCHITECTURE Known gaps brought in line with current behaviour
62
81
 
63
- ## [1.3.0](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.2.0...v1.3.0) (2026-08-03)
82
+ ## [1.3.0](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.2.0...v1.3.0) (2026-08-03)
64
83
 
65
84
 
66
85
  ### Features
67
86
 
68
- * merge cells across columns, down rows, or both, via `merge_cells()` ([39f6e56](https://github.com/Opus-Perpetuus/prettyTables/commit/39f6e56))
87
+ * merge cells across columns, down rows, or both, via `merge_cells()` ([39f6e56](https://github.com/Opus-Perpetuus/flexablelib/commit/39f6e56))
69
88
 
70
89
 
71
90
  ### Performance Improvements
72
91
 
73
- * skip the redundant second measuring pass when the table already fits, and cut per-cell helper overhead; 2000x4 renders in 16.9ms against 30.6ms, making this the fastest of flexablelib, prettytable, tabulate and pandas .to_string() on the same data ([88b01f0](https://github.com/Opus-Perpetuus/prettyTables/commit/88b01f0))
92
+ * skip the redundant second measuring pass when the table already fits, and cut per-cell helper overhead; 2000x4 renders in 16.9ms against 30.6ms, making this the fastest of flexablelib, prettytable, tabulate and pandas .to_string() on the same data ([88b01f0](https://github.com/Opus-Perpetuus/flexablelib/commit/88b01f0))
74
93
 
75
94
 
76
95
  ### Bug Fixes
77
96
 
78
- * the index column no longer continues counting across renders; it is reset explicitly rather than by a side effect of deep-copying the table ([88b01f0](https://github.com/Opus-Perpetuus/prettyTables/commit/88b01f0))
79
- * `is_some_instance` returned None instead of False when nothing matched ([88b01f0](https://github.com/Opus-Perpetuus/prettyTables/commit/88b01f0))
97
+ * the index column no longer continues counting across renders; it is reset explicitly rather than by a side effect of deep-copying the table ([88b01f0](https://github.com/Opus-Perpetuus/flexablelib/commit/88b01f0))
98
+ * `is_some_instance` returned None instead of False when nothing matched ([88b01f0](https://github.com/Opus-Perpetuus/flexablelib/commit/88b01f0))
80
99
 
81
- ## [1.2.0](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.5...v1.2.0) (2026-08-03)
100
+ ## [1.2.0](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.1.5...v1.2.0) (2026-08-03)
82
101
 
83
102
 
84
103
  ### Features
85
104
 
86
- * ANSI colour for headers, borders, columns, rows and individual cells, with NO_COLOR and TTY detection ([f7ea1c9](https://github.com/Opus-Perpetuus/prettyTables/commit/f7ea1c9))
87
- * read from CSV, HTML, dicts, pandas and Excel; write CSV, Markdown, self-contained paginated HTML and Excel ([c54fa06](https://github.com/Opus-Perpetuus/prettyTables/commit/c54fa06))
88
- * parse numeric strings via `parse_str_numbers`, absorbing celulartable's type parsing ([ce5362b](https://github.com/Opus-Perpetuus/prettyTables/commit/ce5362b))
89
- * `max_width` and `too_narrow_message` for tables that cannot fit ([f8309b8](https://github.com/Opus-Perpetuus/prettyTables/commit/f8309b8))
90
- * `Table.missing` sentinel for building tables with gaps ([c54fa06](https://github.com/Opus-Perpetuus/prettyTables/commit/c54fa06))
105
+ * ANSI colour for headers, borders, columns, rows and individual cells, with NO_COLOR and TTY detection ([f7ea1c9](https://github.com/Opus-Perpetuus/flexablelib/commit/f7ea1c9))
106
+ * read from CSV, HTML, dicts, pandas and Excel; write CSV, Markdown, self-contained paginated HTML and Excel ([c54fa06](https://github.com/Opus-Perpetuus/flexablelib/commit/c54fa06))
107
+ * parse numeric strings via `parse_str_numbers`, absorbing celulartable's type parsing ([ce5362b](https://github.com/Opus-Perpetuus/flexablelib/commit/ce5362b))
108
+ * `max_width` and `too_narrow_message` for tables that cannot fit ([f8309b8](https://github.com/Opus-Perpetuus/flexablelib/commit/f8309b8))
109
+ * `Table.missing` sentinel for building tables with gaps ([c54fa06](https://github.com/Opus-Perpetuus/flexablelib/commit/c54fa06))
91
110
 
92
111
 
93
112
  ### Bug Fixes
94
113
 
95
- * measure and pad cells by visible width, fixing alignment for CJK, Hangul and emoji ([7a350d2](https://github.com/Opus-Perpetuus/prettyTables/commit/7a350d2))
96
- * exclude hidden rows from column width measurement ([#22](https://github.com/Opus-Perpetuus/prettyTables/issues/22)) ([e480f4e](https://github.com/Opus-Perpetuus/prettyTables/commit/e480f4e))
97
- * shrink the widest column first instead of every column in proportion ([#16](https://github.com/Opus-Perpetuus/prettyTables/issues/16)) ([842f64e](https://github.com/Opus-Perpetuus/prettyTables/commit/842f64e))
98
- * never hand a column a width budget of zero, which raised from textwrap ([#14](https://github.com/Opus-Perpetuus/prettyTables/issues/14)) ([842f64e](https://github.com/Opus-Perpetuus/prettyTables/commit/842f64e))
99
- * with auto_wrap off, the trimmed table now fits the terminal (Known Issue #2) ([842f64e](https://github.com/Opus-Perpetuus/prettyTables/commit/842f64e))
114
+ * measure and pad cells by visible width, fixing alignment for CJK, Hangul and emoji ([7a350d2](https://github.com/Opus-Perpetuus/flexablelib/commit/7a350d2))
115
+ * exclude hidden rows from column width measurement ([#22](https://github.com/Opus-Perpetuus/flexablelib/issues/22)) ([e480f4e](https://github.com/Opus-Perpetuus/flexablelib/commit/e480f4e))
116
+ * shrink the widest column first instead of every column in proportion ([#16](https://github.com/Opus-Perpetuus/flexablelib/issues/16)) ([842f64e](https://github.com/Opus-Perpetuus/flexablelib/commit/842f64e))
117
+ * never hand a column a width budget of zero, which raised from textwrap ([#14](https://github.com/Opus-Perpetuus/flexablelib/issues/14)) ([842f64e](https://github.com/Opus-Perpetuus/flexablelib/commit/842f64e))
118
+ * with auto_wrap off, the trimmed table now fits the terminal (Known Issue #2) ([842f64e](https://github.com/Opus-Perpetuus/flexablelib/commit/842f64e))
100
119
 
101
120
 
102
121
  ### Performance Improvements
103
122
 
104
- * C extension for text measurement, 17-34x on the hot path, with a pure-Python fallback ([23981d4](https://github.com/Opus-Perpetuus/prettyTables/commit/23981d4))
123
+ * C extension for text measurement, 17-34x on the hot path, with a pure-Python fallback ([23981d4](https://github.com/Opus-Perpetuus/flexablelib/commit/23981d4))
105
124
 
106
- ### [1.1.5](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.4...v1.1.5) (2022-07-11)
125
+ ### [1.1.5](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.1.4...v1.1.5) (2022-07-11)
107
126
 
108
127
 
109
128
  ### Bug Fixes
110
129
 
111
- * Wasn't possible to add empty rows. ([7a94a3f](https://github.com/Opus-Perpetuus/prettyTables/commit/7a94a3f94438ebdab16d21dd80d4c1bc66be872e))
130
+ * Wasn't possible to add empty rows. ([7a94a3f](https://github.com/Opus-Perpetuus/flexablelib/commit/7a94a3f94438ebdab16d21dd80d4c1bc66be872e))
112
131
 
113
- ### [1.1.4](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.3...v1.1.4) (2022-07-11)
132
+ ### [1.1.4](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.1.3...v1.1.4) (2022-07-11)
114
133
 
115
134
 
116
135
  ### Bug Fixes
117
136
 
118
- * Accidental import. ([47e798a](https://github.com/Opus-Perpetuus/prettyTables/commit/47e798a9019b918b47ace50d5fe5683864e5e886))
119
- * Auto trimming fixed. ([92e3a66](https://github.com/Opus-Perpetuus/prettyTables/commit/92e3a668fb931da0225b375d03c72f2ce9e357d0))
120
- * Auto-wrapping fixed. ([4b8d631](https://github.com/Opus-Perpetuus/prettyTables/commit/4b8d631dc9f7dbe65053e25b854dc61c7d6fbb64))
121
- * Autwrapping with index shown fixed. ([cbcb70c](https://github.com/Opus-Perpetuus/prettyTables/commit/cbcb70c8a08c5572553a3b46cad822cc316d5025))
122
- * Columns not showing wen passing less headers in class args. ([1559fe4](https://github.com/Opus-Perpetuus/prettyTables/commit/1559fe41f347130e44f07c67cdd464ca23f0cf68))
123
- * Passing extra headers causes an IndexError. ([e5a3e42](https://github.com/Opus-Perpetuus/prettyTables/commit/e5a3e427cf226d6eb4e58fb658d5068be1700edd))
124
- * Using rows and headers arguments gives error. ([0479cd5](https://github.com/Opus-Perpetuus/prettyTables/commit/0479cd569396db5a08c9b51be7816b53e0e0f8f9))
137
+ * Accidental import. ([47e798a](https://github.com/Opus-Perpetuus/flexablelib/commit/47e798a9019b918b47ace50d5fe5683864e5e886))
138
+ * Auto trimming fixed. ([92e3a66](https://github.com/Opus-Perpetuus/flexablelib/commit/92e3a668fb931da0225b375d03c72f2ce9e357d0))
139
+ * Auto-wrapping fixed. ([4b8d631](https://github.com/Opus-Perpetuus/flexablelib/commit/4b8d631dc9f7dbe65053e25b854dc61c7d6fbb64))
140
+ * Autwrapping with index shown fixed. ([cbcb70c](https://github.com/Opus-Perpetuus/flexablelib/commit/cbcb70c8a08c5572553a3b46cad822cc316d5025))
141
+ * Columns not showing wen passing less headers in class args. ([1559fe4](https://github.com/Opus-Perpetuus/flexablelib/commit/1559fe41f347130e44f07c67cdd464ca23f0cf68))
142
+ * Passing extra headers causes an IndexError. ([e5a3e42](https://github.com/Opus-Perpetuus/flexablelib/commit/e5a3e427cf226d6eb4e58fb658d5068be1700edd))
143
+ * Using rows and headers arguments gives error. ([0479cd5](https://github.com/Opus-Perpetuus/flexablelib/commit/0479cd569396db5a08c9b51be7816b53e0e0f8f9))
125
144
 
126
- ### [1.1.3](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.2...v1.1.3) (2022-05-07)
145
+ ### [1.1.3](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.1.2...v1.1.3) (2022-05-07)
127
146
 
128
147
 
129
148
  ### Bug Fixes
130
149
 
131
- * more accidental imports ([25e4c88](https://github.com/Opus-Perpetuus/prettyTables/commit/25e4c88e0feab8f154547ae159d0d7d8fff0750b))
150
+ * more accidental imports ([25e4c88](https://github.com/Opus-Perpetuus/flexablelib/commit/25e4c88e0feab8f154547ae159d0d7d8fff0750b))
132
151
 
133
- ### [1.1.2](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.1...v1.1.2) (2022-05-07)
152
+ ### [1.1.2](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.1.1...v1.1.2) (2022-05-07)
134
153
 
135
154
 
136
155
  ### Bug Fixes
137
156
 
138
- * accidental import. ([736ab4d](https://github.com/Opus-Perpetuus/prettyTables/commit/736ab4dc281cb766f9726512e3505a5bb17fc0cc))
157
+ * accidental import. ([736ab4d](https://github.com/Opus-Perpetuus/flexablelib/commit/736ab4dc281cb766f9726512e3505a5bb17fc0cc))
139
158
 
140
- ### [1.1.1](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.0...v1.1.1) (2022-05-07)
159
+ ### [1.1.1](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.1.0...v1.1.1) (2022-05-07)
141
160
 
142
161
 
143
162
  ### Bug Fixes
144
163
 
145
- * adding column of different size causing misplaced missing values. ([66abc50](https://github.com/Opus-Perpetuus/prettyTables/commit/66abc5082488c734ffd9329be09f9dc6ea86683b))
146
- * unintended info printing on console. ([560af0a](https://github.com/Opus-Perpetuus/prettyTables/commit/560af0aa8016ab71ad11f9f7ce29375543c192a9))
164
+ * adding column of different size causing misplaced missing values. ([66abc50](https://github.com/Opus-Perpetuus/flexablelib/commit/66abc5082488c734ffd9329be09f9dc6ea86683b))
165
+ * unintended info printing on console. ([560af0a](https://github.com/Opus-Perpetuus/flexablelib/commit/560af0aa8016ab71ad11f9f7ce29375543c192a9))
147
166
 
148
- ## [1.1.0](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.0.0...v1.1.0) (2022-05-07)
167
+ ## [1.1.0](https://github.com/Opus-Perpetuus/flexablelib/compare/v1.0.0...v1.1.0) (2022-05-07)
149
168
 
150
169
 
151
170
  ### Features
152
171
 
153
- * added auto-wrapping for string columns. ([0cacdef](https://github.com/Opus-Perpetuus/prettyTables/commit/0cacdef34c738d0d611440ab393f474f37858ae3))
154
- * added float parsing and alignment ([1a65acd](https://github.com/Opus-Perpetuus/prettyTables/commit/1a65acd7a3fc7deb7331de4bed20a9d276d1a87d))
155
- * added show_index option ([8b8d328](https://github.com/Opus-Perpetuus/prettyTables/commit/8b8d328af591a7d0edd288d80af029837f300f81))
156
- * auto-wrap depends on the auto_wrap option. ([a1e09e5](https://github.com/Opus-Perpetuus/prettyTables/commit/a1e09e50ec913343b5b48b679cf08128ba74a383))
157
- * column data trimming added. ([f53503b](https://github.com/Opus-Perpetuus/prettyTables/commit/f53503bc0b1bf3bd342286ba5cb16354ab8ee4ab))
158
- * show_empty_columns, show_empty_rows options ([a7e4288](https://github.com/Opus-Perpetuus/prettyTables/commit/a7e428845254d68368e9bce6a7fbb4a59fe4046f))
172
+ * added auto-wrapping for string columns. ([0cacdef](https://github.com/Opus-Perpetuus/flexablelib/commit/0cacdef34c738d0d611440ab393f474f37858ae3))
173
+ * added float parsing and alignment ([1a65acd](https://github.com/Opus-Perpetuus/flexablelib/commit/1a65acd7a3fc7deb7331de4bed20a9d276d1a87d))
174
+ * added show_index option ([8b8d328](https://github.com/Opus-Perpetuus/flexablelib/commit/8b8d328af591a7d0edd288d80af029837f300f81))
175
+ * auto-wrap depends on the auto_wrap option. ([a1e09e5](https://github.com/Opus-Perpetuus/flexablelib/commit/a1e09e50ec913343b5b48b679cf08128ba74a383))
176
+ * column data trimming added. ([f53503b](https://github.com/Opus-Perpetuus/flexablelib/commit/f53503bc0b1bf3bd342286ba5cb16354ab8ee4ab))
177
+ * show_empty_columns, show_empty_rows options ([a7e4288](https://github.com/Opus-Perpetuus/flexablelib/commit/a7e428845254d68368e9bce6a7fbb4a59fe4046f))
159
178
 
160
179
 
161
180
  ### Bug Fixes
162
181
 
163
- * add_column omitting columns_with_i ([4cc900d](https://github.com/Opus-Perpetuus/prettyTables/commit/4cc900d25c494fbc2dcf4b58a7c7794c42d22b81))
164
- * auto-wrapping doesn't wrap columns "equally". ([9ba68ab](https://github.com/Opus-Perpetuus/prettyTables/commit/9ba68aba7c8c7494c33682368921802bc5167436))
165
- * empty column and row hiding working bad ([76979e9](https://github.com/Opus-Perpetuus/prettyTables/commit/76979e9b803491e6335cdcca8f7417f99abf8542))
166
- * float columns weren't considering header size ([f8ffce3](https://github.com/Opus-Perpetuus/prettyTables/commit/f8ffce38a2b97d409ca7ba37677280d8ff329c68))
167
- * header wrapping wasn't working ([09b5136](https://github.com/Opus-Perpetuus/prettyTables/commit/09b513653f89dc61331301c2be5b1506366d0fdc))
168
- * hiding empty r/c when showing i behaving bad ([823776a](https://github.com/Opus-Perpetuus/prettyTables/commit/823776ae5b1ca9b9210a8cd8337847a79fd5625f))
169
- * index displays incorrectly when hiding empty rows ([6054dda](https://github.com/Opus-Perpetuus/prettyTables/commit/6054ddae743df58907802c1467f8993d937c7df7))
170
- * large missing val. in float col. causes bad alignment ([565d58c](https://github.com/Opus-Perpetuus/prettyTables/commit/565d58c9db550d63d634c1f49c972a7c8beb7b8f))
171
- * missing value was a normal value and was affecting alignment ([a01d4fa](https://github.com/Opus-Perpetuus/prettyTables/commit/a01d4fa1b7dcc03f3ba78f31b9984ba7a7f4d334))
172
- * read_json not closing json ([6702f53](https://github.com/Opus-Perpetuus/prettyTables/commit/6702f5330f11d1f2a70b811e68f9a26447a065f6))
173
- * table with index wasn't auto-wrapping ([23457a5](https://github.com/Opus-Perpetuus/prettyTables/commit/23457a542733a40931f875db76f2a62939ffa93e))
174
- * when displaying index and adding rows table data messes up. ([3c0a724](https://github.com/Opus-Perpetuus/prettyTables/commit/3c0a7245dd09597ac46028bf31a03d37014c0ccc))
175
- * when showing i table data displays incomplete. ([b33ed42](https://github.com/Opus-Perpetuus/prettyTables/commit/b33ed42d064b1875e70357dedc1b2005ba396379))
176
- * wrapping wasn't working ([cf63647](https://github.com/Opus-Perpetuus/prettyTables/commit/cf63647a741dec0867cb702d75d16c3b0301d3e1))
182
+ * add_column omitting columns_with_i ([4cc900d](https://github.com/Opus-Perpetuus/flexablelib/commit/4cc900d25c494fbc2dcf4b58a7c7794c42d22b81))
183
+ * auto-wrapping doesn't wrap columns "equally". ([9ba68ab](https://github.com/Opus-Perpetuus/flexablelib/commit/9ba68aba7c8c7494c33682368921802bc5167436))
184
+ * empty column and row hiding working bad ([76979e9](https://github.com/Opus-Perpetuus/flexablelib/commit/76979e9b803491e6335cdcca8f7417f99abf8542))
185
+ * float columns weren't considering header size ([f8ffce3](https://github.com/Opus-Perpetuus/flexablelib/commit/f8ffce38a2b97d409ca7ba37677280d8ff329c68))
186
+ * header wrapping wasn't working ([09b5136](https://github.com/Opus-Perpetuus/flexablelib/commit/09b513653f89dc61331301c2be5b1506366d0fdc))
187
+ * hiding empty r/c when showing i behaving bad ([823776a](https://github.com/Opus-Perpetuus/flexablelib/commit/823776ae5b1ca9b9210a8cd8337847a79fd5625f))
188
+ * index displays incorrectly when hiding empty rows ([6054dda](https://github.com/Opus-Perpetuus/flexablelib/commit/6054ddae743df58907802c1467f8993d937c7df7))
189
+ * large missing val. in float col. causes bad alignment ([565d58c](https://github.com/Opus-Perpetuus/flexablelib/commit/565d58c9db550d63d634c1f49c972a7c8beb7b8f))
190
+ * missing value was a normal value and was affecting alignment ([a01d4fa](https://github.com/Opus-Perpetuus/flexablelib/commit/a01d4fa1b7dcc03f3ba78f31b9984ba7a7f4d334))
191
+ * read_json not closing json ([6702f53](https://github.com/Opus-Perpetuus/flexablelib/commit/6702f5330f11d1f2a70b811e68f9a26447a065f6))
192
+ * table with index wasn't auto-wrapping ([23457a5](https://github.com/Opus-Perpetuus/flexablelib/commit/23457a542733a40931f875db76f2a62939ffa93e))
193
+ * when displaying index and adding rows table data messes up. ([3c0a724](https://github.com/Opus-Perpetuus/flexablelib/commit/3c0a7245dd09597ac46028bf31a03d37014c0ccc))
194
+ * when showing i table data displays incomplete. ([b33ed42](https://github.com/Opus-Perpetuus/flexablelib/commit/b33ed42d064b1875e70357dedc1b2005ba396379))
195
+ * wrapping wasn't working ([cf63647](https://github.com/Opus-Perpetuus/flexablelib/commit/cf63647a741dec0867cb702d75d16c3b0301d3e1))
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flexablelib
3
- Version: 2.0.0
4
- Summary: Flexible Table Library — console tables
5
- Home-page: https://github.com/Opus-Perpetuus/prettyTables
3
+ Version: 2.0.3
4
+ Summary: Flexible console and HTML tables for Python
5
+ Home-page: https://github.com/Opus-Perpetuus/flexablelib
6
6
  Download-URL:
7
7
  Author: Benjamin Ramirez
8
8
  Author-email: chilerito12@gmail.com
@@ -52,7 +52,7 @@ Dynamic: summary
52
52
  </p>
53
53
 
54
54
  <p align="center">
55
- <em>Flexible Table Library — format tabular data with pretty styles.</em>
55
+ <em>Flexible Table Library — console and HTML tables for Python.</em>
56
56
  </p>
57
57
 
58
58
  <p align="center">
@@ -69,15 +69,7 @@ Dynamic: summary
69
69
 
70
70
  Flexible Table Library
71
71
 
72
- This is a python package that aims to provide a simple and pretty way of printing tables to the console making use of a class.
73
-
74
- The idea started as an attempt to reproduce the behavior of the [PM2](https://pm2.keymetrics.io) package when it displays tables to show data. Later, heavy inspiration came
75
- of two other python packages:
76
-
77
- - [Jazzband's](https://github.com/jazzband) [prettytable](https://github.com/jazzband/prettytable) (The names are similar by accident). Uses a class too.
78
- - [Astanin's](https://github.com/astanin) [tabulate](https://github.com/astanin/python-tabulate). A very simple to use and efficient package.
79
-
80
- A big part of the behavior of this package was replicated from these.
72
+ Python package for formatting tabular data as console and HTML tables: border styles, cell merges, ANSI colors, per-type and decimal alignment, width fitting, I/O helpers, and optional C-accelerated text measurement.
81
73
 
82
74
  # Installation
83
75
  ``pip install flexablelib`` on Windows.
@@ -326,23 +318,18 @@ from flexablelib.fast import implementation
326
318
  print(implementation()) # 'C extension' or 'pure Python'
327
319
  ```
328
320
 
329
- # Known Issues
330
-
331
- None of the three historical known issues remain:
321
+ # Notes
332
322
 
333
- - A column named ``"i"`` no longer collides with the index column
334
- (`utils.IndexColumnTitle`).
335
- - Exponential numbers align on the decimal / exponent axis with the rest of
336
- the float column.
337
- - Shrinking a float column drops decimals instead of chopping characters, so
338
- decimal alignment survives a terminal fit ([#23](https://github.com/Opus-Perpetuus/prettyTables/issues/23)).
323
+ - A column named ``"i"`` does not collide with the index column (`utils.IndexColumnTitle`).
324
+ - Exponential numbers align on the decimal / exponent axis with the rest of the float column.
325
+ - Shrinking a float column drops decimals instead of chopping characters, so decimal alignment survives a terminal fit ([#23](https://github.com/Opus-Perpetuus/flexablelib/issues/23)).
339
326
 
340
- Open work and the full issue map live in [docs/ISSUES.md](docs/ISSUES.md).
327
+ Open work and the issue map: [docs/ISSUES.md](docs/ISSUES.md).
341
328
 
342
329
  # Project Layout
343
330
 
344
331
  ```
345
- prettyTables/ # GitHub repository (name unchanged)
332
+ flexablelib/ # GitHub repository
346
333
  ├── flexablelib/ the Python package (no runtime dependencies)
347
334
  │ ├── __init__.py public API: Table, TableComposition, SeparatorLine
348
335
  │ ├── table.py the Table class — state and render orchestration
@@ -3,7 +3,7 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <em>Flexible Table Library — format tabular data with pretty styles.</em>
6
+ <em>Flexible Table Library — console and HTML tables for Python.</em>
7
7
  </p>
8
8
 
9
9
  <p align="center">
@@ -20,15 +20,7 @@
20
20
 
21
21
  Flexible Table Library
22
22
 
23
- This is a python package that aims to provide a simple and pretty way of printing tables to the console making use of a class.
24
-
25
- The idea started as an attempt to reproduce the behavior of the [PM2](https://pm2.keymetrics.io) package when it displays tables to show data. Later, heavy inspiration came
26
- of two other python packages:
27
-
28
- - [Jazzband's](https://github.com/jazzband) [prettytable](https://github.com/jazzband/prettytable) (The names are similar by accident). Uses a class too.
29
- - [Astanin's](https://github.com/astanin) [tabulate](https://github.com/astanin/python-tabulate). A very simple to use and efficient package.
30
-
31
- A big part of the behavior of this package was replicated from these.
23
+ Python package for formatting tabular data as console and HTML tables: border styles, cell merges, ANSI colors, per-type and decimal alignment, width fitting, I/O helpers, and optional C-accelerated text measurement.
32
24
 
33
25
  # Installation
34
26
  ``pip install flexablelib`` on Windows.
@@ -277,23 +269,18 @@ from flexablelib.fast import implementation
277
269
  print(implementation()) # 'C extension' or 'pure Python'
278
270
  ```
279
271
 
280
- # Known Issues
281
-
282
- None of the three historical known issues remain:
272
+ # Notes
283
273
 
284
- - A column named ``"i"`` no longer collides with the index column
285
- (`utils.IndexColumnTitle`).
286
- - Exponential numbers align on the decimal / exponent axis with the rest of
287
- the float column.
288
- - Shrinking a float column drops decimals instead of chopping characters, so
289
- decimal alignment survives a terminal fit ([#23](https://github.com/Opus-Perpetuus/prettyTables/issues/23)).
274
+ - A column named ``"i"`` does not collide with the index column (`utils.IndexColumnTitle`).
275
+ - Exponential numbers align on the decimal / exponent axis with the rest of the float column.
276
+ - Shrinking a float column drops decimals instead of chopping characters, so decimal alignment survives a terminal fit ([#23](https://github.com/Opus-Perpetuus/flexablelib/issues/23)).
290
277
 
291
- Open work and the full issue map live in [docs/ISSUES.md](docs/ISSUES.md).
278
+ Open work and the issue map: [docs/ISSUES.md](docs/ISSUES.md).
292
279
 
293
280
  # Project Layout
294
281
 
295
282
  ```
296
- prettyTables/ # GitHub repository (name unchanged)
283
+ flexablelib/ # GitHub repository
297
284
  ├── flexablelib/ the Python package (no runtime dependencies)
298
285
  │ ├── __init__.py public API: Table, TableComposition, SeparatorLine
299
286
  │ ├── table.py the Table class — state and render orchestration
@@ -44,7 +44,7 @@ def _add_cell_spacing(cell: Union[str, Union[List[str], Tuple[str]]],
44
44
  if is_some_instance(cell, tuple, list):
45
45
  # If it is, add the spacing to each part of the cell.
46
46
  spaced = list(map(str, cell)) # Convert to strings to prevent errors.
47
- for part_i, cell_part in enumerate(cell):
47
+ for part_i, cell_part in enumerate(spaced):
48
48
  # Add the spacing to the cell part.
49
49
  # FIX should consider the cell_part length
50
50
  if placeholder_size != 0 and part_i != 0:
@@ -54,10 +54,11 @@ def _add_cell_spacing(cell: Union[str, Union[List[str], Tuple[str]]],
54
54
  else:
55
55
  # If it is not, add the spacing to the cell.
56
56
  # FIX should consider the cell length
57
+ cell_text = str(cell)
57
58
  if placeholder_size != 0:
58
59
  spaced = ''.join([left, diff, right])
59
60
  else:
60
- spaced = ''.join([left, cell, right])
61
+ spaced = ''.join([left, cell_text, right])
61
62
 
62
63
  return spaced
63
64
 
@@ -725,6 +725,23 @@ def __align_single_cell(cell: Union[Any, List[Any], Tuple[Any]],
725
725
  float_column_sizes,
726
726
  DEFAULT_FILL_CHAR,
727
727
  )
728
+ elif to_where == COLUMN_ALIGNS.bytes:
729
+ # Bytes alignment is left-justified (see INDICATOR_RELATIONS). Without
730
+ # this branch the raw cell reaches _add_cell_spacing and TypeErrors on
731
+ # non-str values when callers set *_align / col_alignment to 'b'.
732
+ new_cell = _ljust_cell(
733
+ cell,
734
+ col_width,
735
+ DEFAULT_FILL_CHAR,
736
+ )
737
+ else:
738
+ # Unknown alignment code: still stringify and left-pad so compose()
739
+ # never blows up on a typo or a future alignment name.
740
+ new_cell = _ljust_cell(
741
+ cell,
742
+ col_width,
743
+ DEFAULT_FILL_CHAR,
744
+ )
728
745
  # Add the margin (if any) to the cell.
729
746
  new_cell = _add_cell_spacing(new_cell, margin, margin, 0)
730
747
 
@@ -204,7 +204,12 @@ def _region_bounds(region, layout, index_offset):
204
204
  return None
205
205
 
206
206
  first, last = drawn[0], drawn[-1]
207
- return (layout.spans[first][0], layout.spans[last][1]), layout.spans[first], last
207
+ return (
208
+ (layout.spans[first][0], layout.spans[last][1]),
209
+ layout.spans[first],
210
+ first,
211
+ last,
212
+ )
208
213
 
209
214
 
210
215
  def apply(lines, row_line_map, regions, column_widths, composition,
@@ -235,7 +240,7 @@ def apply(lines, row_line_map, regions, column_widths, composition,
235
240
  bounds = _region_bounds(region, layout, index_offset)
236
241
  if bounds is None:
237
242
  continue
238
- (start, end), (cell_start, cell_end), last_span = bounds
243
+ (start, end), (cell_start, cell_end), first_span, last_span = bounds
239
244
  span_width = end - start - margin * 2
240
245
  if span_width < 1:
241
246
  continue
@@ -277,13 +282,16 @@ def apply(lines, row_line_map, regions, column_widths, composition,
277
282
  # Paint over the separator lines that fall inside the block, so the
278
283
  # merged region reads as one cell top to bottom.
279
284
  #
280
- # Where such a line meets the rule at the block's right edge, that
281
- # junction no longer has a line coming in from the left, so the four
282
- # way character is wrong there. The body rule's own left character is
283
- # exactly the three-way junction needed ('├' where '┼' was).
285
+ # Blanking the horizontal run removes the arms that fed each vertex.
286
+ # Rebuild those vertices from the style's own characters:
287
+ # - right edge, more columns: body left ('├' where '┼' was)
288
+ # - right edge, table border: vertical right ('│' where '┤' was)
289
+ # - left edge, prior columns: body right ('┤' where '┼' was)
290
+ # - left edge, table border: vertical left ('│' where '├' was)
284
291
  body_rule = composition.table_body_line
285
- junction = body_rule.left if body_rule is not None else None
292
+ v_lines = composition.vertical_table_body_lines
286
293
  joins_more_columns = last_span + 1 < len(layout.spans)
294
+ joins_prev_columns = first_span > 0
287
295
 
288
296
  covered = set(target_lines)
289
297
  for line_index in range(min(target_lines), max(target_lines)):
@@ -293,8 +301,17 @@ def apply(lines, row_line_map, regions, column_widths, composition,
293
301
  if visible_width(line) < end:
294
302
  continue
295
303
  rewritten = _repaint(line, start, end, blank)
296
- if junction and joins_more_columns and visible_width(rewritten) > end:
297
- rewritten = _repaint(rewritten, end, end + 1, junction)
304
+ if body_rule is not None or v_lines is not None:
305
+ if visible_width(rewritten) > end:
306
+ if joins_more_columns and body_rule is not None and body_rule.left:
307
+ rewritten = _repaint(rewritten, end, end + 1, body_rule.left)
308
+ elif not joins_more_columns and v_lines is not None and v_lines.right:
309
+ rewritten = _repaint(rewritten, end, end + 1, v_lines.right)
310
+ if start > 0:
311
+ if joins_prev_columns and body_rule is not None and body_rule.right:
312
+ rewritten = _repaint(rewritten, start - 1, start, body_rule.right)
313
+ elif not joins_prev_columns and v_lines is not None and v_lines.left:
314
+ rewritten = _repaint(rewritten, start - 1, start, v_lines.left)
298
315
  lines[line_index] = rewritten
299
316
 
300
317
  return lines
@@ -344,7 +344,8 @@ def from_excel(table_class, path, sheet=None, has_header: bool = True,
344
344
  'Install it with: pip install flexablelib[excel]'
345
345
  )
346
346
 
347
- workbook = load_workbook(filename=path, read_only=True, data_only=True)
347
+ # read_only hides merged cell ranges; we need them to rebuild merges.
348
+ workbook = load_workbook(filename=path, read_only=False, data_only=True)
348
349
  try:
349
350
  if sheet is None:
350
351
  worksheet = workbook.active
@@ -357,14 +358,44 @@ def from_excel(table_class, path, sheet=None, has_header: bool = True,
357
358
  ['' if cell is None else cell for cell in row]
358
359
  for row in worksheet.iter_rows(values_only=True)
359
360
  ]
361
+ merge_ranges = [
362
+ (merged.min_row, merged.min_col, merged.max_row, merged.max_col)
363
+ for merged in worksheet.merged_cells.ranges
364
+ ]
360
365
  finally:
361
366
  workbook.close()
362
367
 
363
368
  if not rows:
364
369
  return table_class(**options)
365
370
  if has_header:
366
- return _new_table(table_class, rows[0], rows[1:], parse_numbers,
367
- **options)
368
- width = max(len(row) for row in rows)
369
- headers = [f'column {i + 1}' for i in range(width)]
370
- return _new_table(table_class, headers, rows, parse_numbers, **options)
371
+ table = _new_table(table_class, rows[0], rows[1:], parse_numbers,
372
+ **options)
373
+ header_rows = 1
374
+ else:
375
+ width = max(len(row) for row in rows)
376
+ headers = [f'column {i + 1}' for i in range(width)]
377
+ table = _new_table(table_class, headers, rows, parse_numbers, **options)
378
+ header_rows = 0
379
+
380
+ # Excel rows/cols are 1-based. Body rows start after the header row when
381
+ # has_header is set. Skip merges that only cover the header.
382
+ for min_row, min_col, max_row, max_col in merge_ranges:
383
+ # Header-only or header-spanning merges are not table body merges.
384
+ if min_row <= header_rows:
385
+ continue
386
+ first_row = min_row - header_rows - 1
387
+ last_row = max_row - header_rows - 1
388
+ first_column = min_col - 1
389
+ last_column = max_col - 1
390
+ if first_row == last_row and first_column == last_column:
391
+ continue
392
+ if last_row < 0 or last_column < 0:
393
+ continue
394
+ if last_row >= table.row_count or last_column >= table.column_count:
395
+ continue
396
+ try:
397
+ table.merge_cells(first_row, first_column, last_row, last_column)
398
+ except ValueError:
399
+ # Overlaps or single cells from odd sheets: skip rather than fail.
400
+ continue
401
+ return table
@@ -1155,13 +1155,21 @@ class Table(object):
1155
1155
  def missing_value(self) -> Any:
1156
1156
  """
1157
1157
  A placeholder for empty cells.
1158
-
1158
+
1159
1159
  Default is::
1160
-
1160
+
1161
1161
  ''
1162
+
1163
+ ``missing_val`` is an alias of this attribute (same name as the
1164
+ ``Table(..., missing_val=...)`` constructor argument).
1162
1165
  """
1163
1166
  return self.__missing_value
1164
1167
 
1168
+ @property
1169
+ def missing_val(self) -> Any:
1170
+ """Alias of :attr:`missing_value`."""
1171
+ return self.__missing_value
1172
+
1165
1173
  @property
1166
1174
  def str_align(self):
1167
1175
  """
@@ -1523,6 +1531,10 @@ class Table(object):
1523
1531
  def missing_value(self, value):
1524
1532
  self.__missing_value = value
1525
1533
 
1534
+ @missing_val.setter
1535
+ def missing_val(self, value):
1536
+ self.__missing_value = value
1537
+
1526
1538
  @str_align.setter
1527
1539
  def str_align(self, value):
1528
1540
  self.__str_align = self.__checked_alignment(value, 'str_align')
@@ -4115,6 +4127,7 @@ class Table(object):
4115
4127
  """
4116
4128
  Build a table from a worksheet in an .xlsx file.
4117
4129
 
4130
+ Excel merged ranges are restored as ``merge_cells`` regions.
4118
4131
  Requires openpyxl: pip install flexablelib[excel]
4119
4132
  """
4120
4133
  from .readers import from_excel
@@ -4183,7 +4196,8 @@ class Table(object):
4183
4196
  Write an .xlsx workbook.
4184
4197
 
4185
4198
  Numbers are written as numbers so the spreadsheet can compute with
4186
- them. Requires openpyxl: pip install flexablelib[excel]
4199
+ them. ``merged_regions`` become real Excel merges. Requires openpyxl:
4200
+ pip install flexablelib[excel]
4187
4201
  """
4188
4202
  from .writers import to_excel
4189
4203
  return to_excel(self, path, sheet_name, include_index, autofit,
@@ -557,4 +557,26 @@ def to_excel(table, path, sheet_name: str = 'Sheet1',
557
557
  if freeze_header:
558
558
  worksheet.freeze_panes = 'A2'
559
559
 
560
+ # Mirror flexablelib merged regions as Excel merged cells. Table coordinates
561
+ # ignore the optional index column and the header row lives on Excel row 1.
562
+ col_offset = 2 if include_index else 1
563
+ for region in getattr(table, 'merged_regions', []):
564
+ start_row = region.first_row + 2
565
+ end_row = region.last_row + 2
566
+ start_col = region.first_column + col_offset
567
+ end_col = region.last_column + col_offset
568
+ top_left = worksheet.cell(row=start_row, column=start_col)
569
+ if region.value is not None:
570
+ top_left.value = _plain(region.value)
571
+ top_left.alignment = Alignment(
572
+ horizontal={'l': 'left', 'r': 'right', 'c': 'center'}.get(
573
+ region.align, 'center'),
574
+ vertical='center',
575
+ wrap_text=True,
576
+ )
577
+ worksheet.merge_cells(
578
+ start_row=start_row, start_column=start_col,
579
+ end_row=end_row, end_column=end_col,
580
+ )
581
+
560
582
  workbook.save(path)
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flexablelib
3
- Version: 2.0.0
4
- Summary: Flexible Table Library — console tables
5
- Home-page: https://github.com/Opus-Perpetuus/prettyTables
3
+ Version: 2.0.3
4
+ Summary: Flexible console and HTML tables for Python
5
+ Home-page: https://github.com/Opus-Perpetuus/flexablelib
6
6
  Download-URL:
7
7
  Author: Benjamin Ramirez
8
8
  Author-email: chilerito12@gmail.com
@@ -52,7 +52,7 @@ Dynamic: summary
52
52
  </p>
53
53
 
54
54
  <p align="center">
55
- <em>Flexible Table Library — format tabular data with pretty styles.</em>
55
+ <em>Flexible Table Library — console and HTML tables for Python.</em>
56
56
  </p>
57
57
 
58
58
  <p align="center">
@@ -69,15 +69,7 @@ Dynamic: summary
69
69
 
70
70
  Flexible Table Library
71
71
 
72
- This is a python package that aims to provide a simple and pretty way of printing tables to the console making use of a class.
73
-
74
- The idea started as an attempt to reproduce the behavior of the [PM2](https://pm2.keymetrics.io) package when it displays tables to show data. Later, heavy inspiration came
75
- of two other python packages:
76
-
77
- - [Jazzband's](https://github.com/jazzband) [prettytable](https://github.com/jazzband/prettytable) (The names are similar by accident). Uses a class too.
78
- - [Astanin's](https://github.com/astanin) [tabulate](https://github.com/astanin/python-tabulate). A very simple to use and efficient package.
79
-
80
- A big part of the behavior of this package was replicated from these.
72
+ Python package for formatting tabular data as console and HTML tables: border styles, cell merges, ANSI colors, per-type and decimal alignment, width fitting, I/O helpers, and optional C-accelerated text measurement.
81
73
 
82
74
  # Installation
83
75
  ``pip install flexablelib`` on Windows.
@@ -326,23 +318,18 @@ from flexablelib.fast import implementation
326
318
  print(implementation()) # 'C extension' or 'pure Python'
327
319
  ```
328
320
 
329
- # Known Issues
330
-
331
- None of the three historical known issues remain:
321
+ # Notes
332
322
 
333
- - A column named ``"i"`` no longer collides with the index column
334
- (`utils.IndexColumnTitle`).
335
- - Exponential numbers align on the decimal / exponent axis with the rest of
336
- the float column.
337
- - Shrinking a float column drops decimals instead of chopping characters, so
338
- decimal alignment survives a terminal fit ([#23](https://github.com/Opus-Perpetuus/prettyTables/issues/23)).
323
+ - A column named ``"i"`` does not collide with the index column (`utils.IndexColumnTitle`).
324
+ - Exponential numbers align on the decimal / exponent axis with the rest of the float column.
325
+ - Shrinking a float column drops decimals instead of chopping characters, so decimal alignment survives a terminal fit ([#23](https://github.com/Opus-Perpetuus/flexablelib/issues/23)).
339
326
 
340
- Open work and the full issue map live in [docs/ISSUES.md](docs/ISSUES.md).
327
+ Open work and the issue map: [docs/ISSUES.md](docs/ISSUES.md).
341
328
 
342
329
  # Project Layout
343
330
 
344
331
  ```
345
- prettyTables/ # GitHub repository (name unchanged)
332
+ flexablelib/ # GitHub repository
346
333
  ├── flexablelib/ the Python package (no runtime dependencies)
347
334
  │ ├── __init__.py public API: Table, TableComposition, SeparatorLine
348
335
  │ ├── table.py the Table class — state and render orchestration
@@ -28,6 +28,7 @@ flexablelib.egg-info/requires.txt
28
28
  flexablelib.egg-info/top_level.txt
29
29
  tests/test_cells.py
30
30
  tests/test_columns.py
31
+ tests/test_excel.py
31
32
  tests/test_features.py
32
33
  tests/test_issues.py
33
34
  tests/test_merges.py
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "flexablelib",
3
- "version": "2.0.0",
4
- "description": "Flexible Table Library \u2014 format tabular data for the console.",
3
+ "version": "2.0.3",
4
+ "description": "Flexible console and HTML tables for Python: styles, merges, colors, widths, decimal alignment.",
5
5
  "main": "__init__.py",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -12,14 +12,14 @@
12
12
  },
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "git+https://github.com/Opus-Perpetuus/prettyTables.git"
15
+ "url": "git+https://github.com/Opus-Perpetuus/flexablelib.git"
16
16
  },
17
17
  "author": "Kyostenas",
18
18
  "license": "MIT",
19
19
  "bugs": {
20
- "url": "https://github.com/Opus-Perpetuus/prettyTables/issues"
20
+ "url": "https://github.com/Opus-Perpetuus/flexablelib/issues"
21
21
  },
22
- "homepage": "https://github.com/Opus-Perpetuus/prettyTables#readme",
22
+ "homepage": "https://github.com/Opus-Perpetuus/flexablelib#readme",
23
23
  "config": {
24
24
  "commitzen": {
25
25
  "path": "cz-conventional-changelog"
@@ -18,12 +18,12 @@ setup(
18
18
  name = 'flexablelib',
19
19
  packages = ['flexablelib'],
20
20
  version = read_json(f'.{os.sep}package.json')['version'],
21
- description = 'Flexible Table Library — console tables',
21
+ description = 'Flexible console and HTML tables for Python',
22
22
  long_description=read_file('README.md'),
23
23
  long_description_content_type='text/markdown',
24
24
  author = 'Benjamin Ramirez',
25
25
  author_email = 'chilerito12@gmail.com',
26
- url = 'https://github.com/Opus-Perpetuus/prettyTables',
26
+ url = 'https://github.com/Opus-Perpetuus/flexablelib',
27
27
  license='MIT',
28
28
  download_url = '',
29
29
  keywords = ['console', 'graphics'],
@@ -0,0 +1,110 @@
1
+ """
2
+ Excel import / export.
3
+
4
+ Round-trips plain tables and merged regions through openpyxl workbooks.
5
+ """
6
+
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+
11
+ from flexablelib import Table
12
+
13
+
14
+ pytest.importorskip('openpyxl')
15
+
16
+
17
+ def build_table():
18
+ table = Table()
19
+ table.add_column('Region', ['Norte', 'Norte', 'Sur', 'Sur'])
20
+ table.add_column('Month', ['Jan', 'Feb', 'Jan', 'Feb'])
21
+ table.add_column('Sales', [120.5, 98.25, 210.0, 175.75])
22
+ return table
23
+
24
+
25
+ def test_to_excel_and_from_excel_round_trip_values(tmp_path):
26
+ path = tmp_path / 'plain.xlsx'
27
+ table = build_table()
28
+ table.to_excel(path)
29
+
30
+ loaded = Table.from_excel(path)
31
+
32
+ assert loaded.headers == ['Region', 'Month', 'Sales']
33
+ assert loaded.rows[0][0] == 'Norte'
34
+ assert loaded.rows[0][2] == 120.5
35
+
36
+
37
+ def test_to_excel_writes_merged_cells(tmp_path):
38
+ from openpyxl import load_workbook
39
+
40
+ path = tmp_path / 'merged.xlsx'
41
+ table = build_table()
42
+ table.merge_cells(0, 0, last_row=1, value='Norte')
43
+ table.merge_cells(0, 1, last_column=2, value='Q1')
44
+ table.to_excel(path)
45
+
46
+ workbook = load_workbook(path)
47
+ ranges = {str(r) for r in workbook.active.merged_cells.ranges}
48
+ workbook.close()
49
+
50
+ assert 'A2:A3' in ranges
51
+ assert 'B2:C2' in ranges
52
+
53
+
54
+ def test_from_excel_restores_merged_regions(tmp_path):
55
+ path = tmp_path / 'round.xlsx'
56
+ table = build_table()
57
+ table.merge_cells(0, 0, last_row=1, value='Norte')
58
+ table.merge_cells(2, 0, last_column=1, value='Sur block')
59
+ table.to_excel(path)
60
+
61
+ loaded = Table.from_excel(path)
62
+
63
+ assert len(loaded.merged_regions) == 2
64
+ regions = {(r.first_row, r.first_column, r.last_row, r.last_column)
65
+ for r in loaded.merged_regions}
66
+ assert (0, 0, 1, 0) in regions
67
+ assert (2, 0, 2, 1) in regions
68
+ assert 'Norte' in str(loaded)
69
+ assert 'Sur block' in str(loaded)
70
+
71
+
72
+ def test_to_excel_shifts_merges_when_index_included(tmp_path):
73
+ from openpyxl import load_workbook
74
+
75
+ path = tmp_path / 'indexed.xlsx'
76
+ table = build_table()
77
+ table.show_index = True
78
+ table.merge_cells(0, 0, last_row=1, value='Norte')
79
+ table.to_excel(path, include_index=True)
80
+
81
+ workbook = load_workbook(path)
82
+ ranges = {str(r) for r in workbook.active.merged_cells.ranges}
83
+ workbook.close()
84
+
85
+ # Index column is A; body Region is B → B2:B3
86
+ assert 'B2:B3' in ranges
87
+
88
+
89
+ def test_from_excel_sheet_selection(tmp_path):
90
+ from openpyxl import Workbook
91
+
92
+ path = tmp_path / 'multi.xlsx'
93
+ workbook = Workbook()
94
+ first = workbook.active
95
+ first.title = 'One'
96
+ first.append(['A'])
97
+ first.append([1])
98
+ second = workbook.create_sheet('Two')
99
+ second.append(['X', 'Y'])
100
+ second.append(['x1', 'y1'])
101
+ second.append(['x2', 'y2'])
102
+ second.merge_cells('A2:A3')
103
+ workbook.save(path)
104
+ workbook.close()
105
+
106
+ loaded = Table.from_excel(path, sheet='Two')
107
+ assert loaded.headers == ['X', 'Y']
108
+ assert len(loaded.merged_regions) == 1
109
+ region = loaded.merged_regions[0]
110
+ assert (region.first_row, region.first_column, region.last_row, region.last_column) == (0, 0, 1, 0)
@@ -216,3 +216,43 @@ def test_the_package_can_be_star_imported():
216
216
  assert 'Table' in namespace
217
217
  assert 'TableComposition' in namespace
218
218
  assert 'SeparatorLine' in namespace
219
+
220
+
221
+ def test_bytes_alignment_code_renders_without_typeerror():
222
+ """``COLUMN_ALIGNS.bytes`` ('b') must justify like left, not crash.
223
+
224
+ Forcing ``*_align`` / ``col_alignment`` to ``'b'`` used to skip every
225
+ justify branch in ``__align_single_cell``, so the raw int/bytes cell hit
226
+ ``_add_cell_spacing`` and raised ``TypeError``.
227
+ """
228
+ table = Table()
229
+ table.add_column('Name', ['Jade', 'John'])
230
+ table.add_column('Age', [20, 30])
231
+ table.add_column('Blob', [b'abc', b'xy'])
232
+ table.col_alignment = 'b'
233
+ rendered = str(table)
234
+ assert 'Jade' in rendered
235
+ assert '20' in rendered
236
+ assert "b'abc'" in rendered or 'abc' in rendered
237
+
238
+ only_bytes = Table()
239
+ only_bytes.add_column('Blob', [b'hello', b'world'])
240
+ only_bytes.col_alignment = 'b'
241
+ assert 'hello' in str(only_bytes)
242
+
243
+ ints = Table()
244
+ ints.add_column('n', [1, 2, 3])
245
+ ints.int_align = 'b'
246
+ assert '1' in str(ints)
247
+
248
+
249
+ def test_missing_val_alias_matches_missing_value():
250
+ table = Table()
251
+ table.add_column('a', ['x'])
252
+ table.add_row([])
253
+ table.missing_val = 'n/a'
254
+ assert table.missing_value == 'n/a'
255
+ assert 'n/a' in str(table)
256
+ table.missing_value = '?'
257
+ assert table.missing_val == '?'
258
+ assert '?' in str(table)
@@ -51,6 +51,65 @@ def test_a_vertical_merge_removes_the_rules_between_its_rows():
51
51
  assert rendered.count('Norte') == 1
52
52
 
53
53
 
54
+
55
+ def test_vertical_merge_turns_left_border_into_an_edge():
56
+ """Vertices on a body rule inside a vertical merge must become edges.
57
+
58
+ The horizontal arms into the merged cell are gone, so a left-border
59
+ '├' becomes the vertical edge '│', and the right junction keeps the
60
+ three-way '├' that opens the remaining columns.
61
+ """
62
+ table = build_table()
63
+ table.merge_cells(0, 0, last_row=1, value='Norte')
64
+
65
+ sep = next(
66
+ line for line in str(table).splitlines()
67
+ if '├───────┼────────┤' in line or line.startswith('│ ├')
68
+ )
69
+
70
+ assert sep.startswith('│')
71
+ assert '├───────┼────────┤' in sep
72
+ assert not sep.startswith('├')
73
+
74
+
75
+ def test_vertical_merge_in_middle_column_uses_left_and_right_tees():
76
+ table = build_table()
77
+ table.merge_cells(0, 1, last_row=1, value='M')
78
+
79
+ sep = next(line for line in str(table).splitlines() if ' ' in line and '┤' in line and line.count('├') >= 1)
80
+
81
+ assert '├────────┤ ├────────┤' in sep
82
+
83
+
84
+ def test_vertical_merge_on_last_column_turns_right_border_into_an_edge():
85
+ table = build_table()
86
+ table.merge_cells(0, 2, last_row=1, value='S')
87
+
88
+ sep = next(line for line in str(table).splitlines() if line.endswith('│') and '┤ │' in line)
89
+
90
+ assert sep.endswith('│')
91
+ assert '├────────┼───────┤ │' in sep
92
+
93
+
94
+ def test_vertical_merge_vertices_follow_grid_ascii_style():
95
+ table = build_table('grid')
96
+ table.merge_cells(0, 0, last_row=1, value='Norte')
97
+
98
+ sep = next(line for line in str(table).splitlines() if '+-------+' in line and line.startswith('|'))
99
+
100
+ assert sep.startswith('| +')
101
+
102
+
103
+ def test_vertical_merge_vertices_follow_bold_borderline_style():
104
+ table = build_table('bold_borderline')
105
+ table.merge_cells(0, 0, last_row=1, value='Norte')
106
+
107
+ sep = next(line for line in str(table).splitlines() if '╟───────┼────────╢' in line)
108
+
109
+ assert sep.startswith('║')
110
+ assert '║ ╟───────┼────────╢' in sep
111
+
112
+
54
113
  def test_a_block_merge_covers_both_directions():
55
114
  table = build_table()
56
115
  table.merge_cells(0, 0, 1, 1, value='Block')
File without changes
File without changes
File without changes