flexablelib 2.0.0__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.
- flexablelib-2.0.0/CHANGELOG.md +176 -0
- flexablelib-2.0.0/LICENSE +21 -0
- flexablelib-2.0.0/MANIFEST.in +7 -0
- flexablelib-2.0.0/PKG-INFO +372 -0
- flexablelib-2.0.0/README.md +323 -0
- flexablelib-2.0.0/flexablelib/__init__.py +6 -0
- flexablelib-2.0.0/flexablelib/_speedups.c +475 -0
- flexablelib-2.0.0/flexablelib/_width_tables.h +524 -0
- flexablelib-2.0.0/flexablelib/cells.py +522 -0
- flexablelib-2.0.0/flexablelib/colors.py +195 -0
- flexablelib-2.0.0/flexablelib/columns.py +888 -0
- flexablelib-2.0.0/flexablelib/fast.py +81 -0
- flexablelib-2.0.0/flexablelib/merges.py +300 -0
- flexablelib-2.0.0/flexablelib/options.py +88 -0
- flexablelib-2.0.0/flexablelib/readers.py +370 -0
- flexablelib-2.0.0/flexablelib/style_compositions.py +872 -0
- flexablelib-2.0.0/flexablelib/table.py +4197 -0
- flexablelib-2.0.0/flexablelib/table_strings.py +711 -0
- flexablelib-2.0.0/flexablelib/text_width.py +480 -0
- flexablelib-2.0.0/flexablelib/utils.py +232 -0
- flexablelib-2.0.0/flexablelib/writers.py +560 -0
- flexablelib-2.0.0/flexablelib.egg-info/PKG-INFO +372 -0
- flexablelib-2.0.0/flexablelib.egg-info/SOURCES.txt +40 -0
- flexablelib-2.0.0/flexablelib.egg-info/dependency_links.txt +1 -0
- flexablelib-2.0.0/flexablelib.egg-info/requires.txt +14 -0
- flexablelib-2.0.0/flexablelib.egg-info/top_level.txt +1 -0
- flexablelib-2.0.0/package.json +47 -0
- flexablelib-2.0.0/setup.cfg +7 -0
- flexablelib-2.0.0/setup.py +58 -0
- flexablelib-2.0.0/tests/test_cells.py +249 -0
- flexablelib-2.0.0/tests/test_columns.py +302 -0
- flexablelib-2.0.0/tests/test_features.py +218 -0
- flexablelib-2.0.0/tests/test_issues.py +859 -0
- flexablelib-2.0.0/tests/test_merges.py +422 -0
- flexablelib-2.0.0/tests/test_readme_examples.py +266 -0
- flexablelib-2.0.0/tests/test_styles.py +189 -0
- flexablelib-2.0.0/tests/test_text_width.py +257 -0
- flexablelib-2.0.0/tests/test_two_pass_measurement.py +266 -0
- flexablelib-2.0.0/tests/test_upstream_issues.py +415 -0
- flexablelib-2.0.0/tools/benchmark.py +111 -0
- flexablelib-2.0.0/tools/generate_width_tables.py +112 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
## [2.0.0](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.4.1...v2.0.0) (2026-10-28)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### ⚠ BREAKING CHANGES
|
|
9
|
+
|
|
10
|
+
* package renamed from `prettyTables` to `flexablelib` (`from flexablelib import Table`)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* Flexible Table Library identity: PyPI name `flexablelib`, C extension `flexablelib._speedups`
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* colour merge tests pin `use_colors=True` so CI without a TTY still asserts ANSI codes
|
|
21
|
+
|
|
22
|
+
## [1.4.1](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.4.0...v1.4.1) (2026-08-03)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* `column_max_width` now wraps or trims cell content to the cap (was only
|
|
28
|
+
changing the measured width number, so long cells still overflowed)
|
|
29
|
+
|
|
30
|
+
## [1.4.0](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.3.0...v1.4.0) (2026-08-03)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Features
|
|
34
|
+
|
|
35
|
+
* cell formatters: `float_format`, `int_format`, `custom_format`, and `leading_zeros`
|
|
36
|
+
* per-column `column_min_width` / `column_max_width`
|
|
37
|
+
* `header_align` independent of body alignment
|
|
38
|
+
* `add_divider()` / `clear_dividers()` for horizontal rules between rows
|
|
39
|
+
* table `title` drawn above the frame
|
|
40
|
+
* `sort_by` / `sort_reverse` and `row_filter` at render time (storage unchanged)
|
|
41
|
+
* Jupyter `_repr_html_()` via a bare HTML table
|
|
42
|
+
* `shape` property `(rows, columns)`
|
|
43
|
+
* `table_align` and `expand_to_window` wired into render
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
### Bug Fixes
|
|
47
|
+
|
|
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))
|
|
51
|
+
* column named `"i"` no longer collides with the index column
|
|
52
|
+
* exponential numbers align with the float column
|
|
53
|
+
* tabs, emoji VS16, empty header-only tables, markdown alignment colons, and other upstream regressions
|
|
54
|
+
* wide-character wrap at width 1 no longer invents a blank line
|
|
55
|
+
* header-only tables survive a narrow `max_width` without `IndexError`
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
### Documentation
|
|
59
|
+
|
|
60
|
+
* `docs/ISSUES.md` maps every tracker issue to its fix and tests
|
|
61
|
+
* README Known Issues and ARCHITECTURE Known gaps brought in line with current behaviour
|
|
62
|
+
|
|
63
|
+
## [1.3.0](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.2.0...v1.3.0) (2026-08-03)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
### Features
|
|
67
|
+
|
|
68
|
+
* merge cells across columns, down rows, or both, via `merge_cells()` ([39f6e56](https://github.com/Opus-Perpetuus/prettyTables/commit/39f6e56))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
### Performance Improvements
|
|
72
|
+
|
|
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))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
### Bug Fixes
|
|
77
|
+
|
|
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))
|
|
80
|
+
|
|
81
|
+
## [1.2.0](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.5...v1.2.0) (2026-08-03)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
### Features
|
|
85
|
+
|
|
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))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
### Bug Fixes
|
|
94
|
+
|
|
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))
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
### Performance Improvements
|
|
103
|
+
|
|
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))
|
|
105
|
+
|
|
106
|
+
### [1.1.5](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.4...v1.1.5) (2022-07-11)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
### Bug Fixes
|
|
110
|
+
|
|
111
|
+
* Wasn't possible to add empty rows. ([7a94a3f](https://github.com/Opus-Perpetuus/prettyTables/commit/7a94a3f94438ebdab16d21dd80d4c1bc66be872e))
|
|
112
|
+
|
|
113
|
+
### [1.1.4](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.3...v1.1.4) (2022-07-11)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
### Bug Fixes
|
|
117
|
+
|
|
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))
|
|
125
|
+
|
|
126
|
+
### [1.1.3](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.2...v1.1.3) (2022-05-07)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
### Bug Fixes
|
|
130
|
+
|
|
131
|
+
* more accidental imports ([25e4c88](https://github.com/Opus-Perpetuus/prettyTables/commit/25e4c88e0feab8f154547ae159d0d7d8fff0750b))
|
|
132
|
+
|
|
133
|
+
### [1.1.2](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.1...v1.1.2) (2022-05-07)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
### Bug Fixes
|
|
137
|
+
|
|
138
|
+
* accidental import. ([736ab4d](https://github.com/Opus-Perpetuus/prettyTables/commit/736ab4dc281cb766f9726512e3505a5bb17fc0cc))
|
|
139
|
+
|
|
140
|
+
### [1.1.1](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.1.0...v1.1.1) (2022-05-07)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
### Bug Fixes
|
|
144
|
+
|
|
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))
|
|
147
|
+
|
|
148
|
+
## [1.1.0](https://github.com/Opus-Perpetuus/prettyTables/compare/v1.0.0...v1.1.0) (2022-05-07)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
### Features
|
|
152
|
+
|
|
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))
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
### Bug Fixes
|
|
162
|
+
|
|
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))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-2022 Benjamin Ramirez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flexablelib
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Flexible Table Library — console tables
|
|
5
|
+
Home-page: https://github.com/Opus-Perpetuus/prettyTables
|
|
6
|
+
Download-URL:
|
|
7
|
+
Author: Benjamin Ramirez
|
|
8
|
+
Author-email: chilerito12@gmail.com
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: console,graphics
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Provides-Extra: pandas
|
|
28
|
+
Requires-Dist: pandas>=1.0; extra == "pandas"
|
|
29
|
+
Provides-Extra: excel
|
|
30
|
+
Requires-Dist: openpyxl>=3.0; extra == "excel"
|
|
31
|
+
Provides-Extra: html
|
|
32
|
+
Requires-Dist: lxml>=4.0; extra == "html"
|
|
33
|
+
Provides-Extra: all
|
|
34
|
+
Requires-Dist: pandas>=1.0; extra == "all"
|
|
35
|
+
Requires-Dist: openpyxl>=3.0; extra == "all"
|
|
36
|
+
Requires-Dist: lxml>=4.0; extra == "all"
|
|
37
|
+
Dynamic: author
|
|
38
|
+
Dynamic: author-email
|
|
39
|
+
Dynamic: classifier
|
|
40
|
+
Dynamic: description
|
|
41
|
+
Dynamic: description-content-type
|
|
42
|
+
Dynamic: home-page
|
|
43
|
+
Dynamic: keywords
|
|
44
|
+
Dynamic: license
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
Dynamic: provides-extra
|
|
47
|
+
Dynamic: requires-python
|
|
48
|
+
Dynamic: summary
|
|
49
|
+
|
|
50
|
+
<p align="center">
|
|
51
|
+
<img src="logos/export/logo.svg" alt="flexablelib" width="440">
|
|
52
|
+
</p>
|
|
53
|
+
|
|
54
|
+
<p align="center">
|
|
55
|
+
<em>Flexible Table Library — format tabular data with pretty styles.</em>
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
<p align="center">
|
|
59
|
+
<a href="https://pypi.org/project/flexablelib/"><img alt="PyPI version" src="https://img.shields.io/pypi/v/flexablelib?style=flat-square&color=4338CA&logo=pypi&logoColor=white"></a>
|
|
60
|
+
<a href="https://pypi.org/project/flexablelib/"><img alt="Python versions" src="https://img.shields.io/pypi/pyversions/flexablelib?style=flat-square&color=4338CA&logo=python&logoColor=white"></a>
|
|
61
|
+
<a href="https://pypi.org/project/flexablelib/"><img alt="Downloads per month" src="https://img.shields.io/pypi/dm/flexablelib?style=flat-square&color=F59E0B"></a>
|
|
62
|
+
<a href="https://pypi.org/project/flexablelib/"><img alt="Development status" src="https://img.shields.io/pypi/status/flexablelib?style=flat-square&color=F59E0B"></a>
|
|
63
|
+
<a href="LICENSE"><img alt="License" src="https://img.shields.io/pypi/l/flexablelib?style=flat-square&color=64748B"></a>
|
|
64
|
+
</p>
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
# **flexablelib**
|
|
69
|
+
|
|
70
|
+
Flexible Table Library
|
|
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.
|
|
81
|
+
|
|
82
|
+
# Installation
|
|
83
|
+
``pip install flexablelib`` on Windows.
|
|
84
|
+
|
|
85
|
+
``pip3 install flexablelib`` on Linux
|
|
86
|
+
|
|
87
|
+
# Usage
|
|
88
|
+
Creating a table is simple.
|
|
89
|
+
### Code Example
|
|
90
|
+
```
|
|
91
|
+
from flexablelib import Table
|
|
92
|
+
|
|
93
|
+
new_table = Table()
|
|
94
|
+
print(new_table)
|
|
95
|
+
```
|
|
96
|
+
### Output
|
|
97
|
+
```
|
|
98
|
+
++
|
|
99
|
+
++
|
|
100
|
+
++
|
|
101
|
+
```
|
|
102
|
+
This is an empty table. It has no data so it only displays this strange thing.
|
|
103
|
+
|
|
104
|
+
A table that has columns but no rows — a query that came back empty — shows
|
|
105
|
+
its headers rather than raising:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
┌──────┬───────┐
|
|
109
|
+
│ name │ value │
|
|
110
|
+
╞══════╪═══════╡
|
|
111
|
+
└──────┴───────┘
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
It's possible to add data as columns or rows, or even alternating each one. Any untitled column will be named automatically.
|
|
115
|
+
|
|
116
|
+
### Code Example
|
|
117
|
+
```
|
|
118
|
+
new_table.add_column('Name', ['Jade', 'John', 'Jane'])
|
|
119
|
+
new_table.add_column('Age', [20, 30, 40])
|
|
120
|
+
new_table.add_column('Results', [9.651, 3, 245.7])
|
|
121
|
+
print(new_table)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Output
|
|
125
|
+
```
|
|
126
|
+
+----------------------+
|
|
127
|
+
| Name Age Results |
|
|
128
|
+
+======+=====+=========+
|
|
129
|
+
| Jade | 20 | 9.651 |
|
|
130
|
+
| John | 30 | 3 |
|
|
131
|
+
| Jane | 40 | 245.7 |
|
|
132
|
+
+------+-----+---------+
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Code Example
|
|
136
|
+
```
|
|
137
|
+
new_table = Table()
|
|
138
|
+
new_table.add_column('Name', ['Jade', 'John', 'Jane'])
|
|
139
|
+
new_table.add_column('Age', [20, 30, 40])
|
|
140
|
+
new_table.add_column('Test\nResults', [9.651, 3, 245.7])
|
|
141
|
+
new_table.add_row(['Piotr\nBaltimore', 27, 3.5])
|
|
142
|
+
new_table.add_row(['Sam', 21, 0.6519])
|
|
143
|
+
print(new_table)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Output
|
|
147
|
+
```
|
|
148
|
+
+----------------------------+
|
|
149
|
+
| Name Age Test |
|
|
150
|
+
| Results |
|
|
151
|
+
+===========+=====+==========+
|
|
152
|
+
| Jade | 20 | 9.651 |
|
|
153
|
+
| John | 30 | 3 |
|
|
154
|
+
| Jane | 40 | 245.7 |
|
|
155
|
+
| Piotr | 27 | 3.5 |
|
|
156
|
+
| Baltimore | | |
|
|
157
|
+
| Sam | 21 | 0.6519 |
|
|
158
|
+
+-----------+-----+----------+
|
|
159
|
+
```
|
|
160
|
+
As it is visible, the table will format automatically new lines and data types, for now without trying to parse strings that could be converted to another type.
|
|
161
|
+
|
|
162
|
+
The ``Table`` class offers a variety of options that allow things like showing the index of each row, changing the style of the table, hiding the headers, etc.
|
|
163
|
+
|
|
164
|
+
See style examples [here](/style_examples.md).
|
|
165
|
+
|
|
166
|
+
### Code Example
|
|
167
|
+
```
|
|
168
|
+
new_table = Table()
|
|
169
|
+
new_table.add_column('Name', ['Jade', 'John'])
|
|
170
|
+
new_table.add_column('Age', [20, 30])
|
|
171
|
+
new_table.add_column('Test\nResults', [9.651, 3, 245.7])
|
|
172
|
+
new_table.add_row(['Piotr\nBaltimore', 27, 3.5])
|
|
173
|
+
new_table.add_row(['Sam', 21])
|
|
174
|
+
new_table.show_index = True
|
|
175
|
+
new_table.style_name = 'pretty_columns'
|
|
176
|
+
new_table.missing_value = '?'
|
|
177
|
+
print(new_table)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Output
|
|
181
|
+
```
|
|
182
|
+
╒═══╤═══════════╤═════╤═════════╕
|
|
183
|
+
│ i │ Name │ Age │ Test │
|
|
184
|
+
│ │ │ │ Results │
|
|
185
|
+
╞═══╪═══════════╪═════╪═════════╡
|
|
186
|
+
│ 0 │ Jade │ 20 │ 9.651 │
|
|
187
|
+
│ 1 │ John │ 30 │ 3 │
|
|
188
|
+
│ 2 │ ? │ ? │ 245.7 │
|
|
189
|
+
│ 3 │ Piotr │ 27 │ 3.5 │
|
|
190
|
+
│ │ Baltimore │ │ │
|
|
191
|
+
│ 4 │ Sam │ 21 │ ? │
|
|
192
|
+
╘═══╧═══════════╧═════╧═════════╛
|
|
193
|
+
```
|
|
194
|
+
The missing value aligns as if it was of the same type of the other data in the column.
|
|
195
|
+
|
|
196
|
+
This shows how to get the row and column count. If the index is shown, this count remains unaffected by that column, although, you can get the internal count.
|
|
197
|
+
|
|
198
|
+
### Code Example
|
|
199
|
+
```
|
|
200
|
+
new_table.show_index = False
|
|
201
|
+
new_table.show_headers = False
|
|
202
|
+
print(new_table)
|
|
203
|
+
print('row:', new_table.row_count)
|
|
204
|
+
print('columns:', new_table.column_count)
|
|
205
|
+
new_table.show_index = True
|
|
206
|
+
print(new_table)
|
|
207
|
+
print('internal_row_count:', new_table.internal_row_count)
|
|
208
|
+
print('internal_column_count:', new_table.internal_column_count)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Output
|
|
212
|
+
```
|
|
213
|
+
╒═══════════╤════╤═════════╕
|
|
214
|
+
│ Jade │ 20 │ 9.651 │
|
|
215
|
+
│ John │ 30 │ 3 │
|
|
216
|
+
│ ? │ ? │ 245.7 │
|
|
217
|
+
│ Piotr │ 27 │ 3.5 │
|
|
218
|
+
│ Baltimore │ │ │
|
|
219
|
+
│ Sam │ 21 │ ? │
|
|
220
|
+
╘═══════════╧════╧═════════╛
|
|
221
|
+
row: 5
|
|
222
|
+
columns: 3
|
|
223
|
+
╒═══╤═══════════╤════╤═════════╕
|
|
224
|
+
│ 0 │ Jade │ 20 │ 9.651 │
|
|
225
|
+
│ 1 │ John │ 30 │ 3 │
|
|
226
|
+
│ 2 │ ? │ ? │ 245.7 │
|
|
227
|
+
│ 3 │ Piotr │ 27 │ 3.5 │
|
|
228
|
+
│ │ Baltimore │ │ │
|
|
229
|
+
│ 4 │ Sam │ 21 │ ? │
|
|
230
|
+
╘═══╧═══════════╧════╧═════════╛
|
|
231
|
+
internal_row_count: 5
|
|
232
|
+
internal_column_count: 4
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
# Colour
|
|
236
|
+
|
|
237
|
+
Colour the header, the borders, whole columns, whole rows, or individual cells.
|
|
238
|
+
Specs accept names, attributes, 256-colour indexes and hex triples.
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
table.header_color = 'bold cyan'
|
|
242
|
+
table.border_color = 'grey'
|
|
243
|
+
table.column_colors = {'Service': 'bright_white'}
|
|
244
|
+
table.color_rule = lambda value, row, column: (
|
|
245
|
+
'red' if column == 'Delta' and value < 0 else None
|
|
246
|
+
)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`color_rule` receives the original value, so numeric comparisons work directly.
|
|
250
|
+
|
|
251
|
+
Colour is emitted only to a terminal by default, and never when `NO_COLOR` is
|
|
252
|
+
set. `FORCE_COLOR` or `table.use_colors = True` overrides that. Because
|
|
253
|
+
`compose()` returns a string you may send anywhere, the default errs toward not
|
|
254
|
+
embedding escape sequences in something bound for a file.
|
|
255
|
+
|
|
256
|
+
Widths are measured in terminal columns, not characters, so coloured cells and
|
|
257
|
+
CJK or emoji data stay aligned.
|
|
258
|
+
|
|
259
|
+
# Reading and writing
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
Table.from_csv('sales.csv') # numeric columns parsed and aligned
|
|
263
|
+
Table.from_html(markup) # standard library parser, no dependency
|
|
264
|
+
Table.from_dicts(records)
|
|
265
|
+
Table.from_pandas(dataframe) # pip install flexablelib[pandas]
|
|
266
|
+
Table.from_excel('report.xlsx') # pip install flexablelib[excel]
|
|
267
|
+
|
|
268
|
+
table.to_csv('out.csv')
|
|
269
|
+
table.to_markdown()
|
|
270
|
+
table.to_html('report.html', paginate=25)
|
|
271
|
+
table.to_excel('report.xlsx')
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
`to_html` writes one self-contained file — the stylesheet and the sorting,
|
|
275
|
+
filtering and pagination script are inline — so it works offline and from a
|
|
276
|
+
`file://` URL.
|
|
277
|
+
|
|
278
|
+
Text formats deliver everything as strings, and a column of strings is
|
|
279
|
+
left-aligned. `parse_str_numbers` converts numeric-looking text so it aligns as
|
|
280
|
+
numbers; the readers turn it on for you:
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
table.parse_str_numbers = True
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Values with leading zeros are left alone, so `'007'` stays a string.
|
|
287
|
+
|
|
288
|
+
# Merging cells
|
|
289
|
+
|
|
290
|
+
Render a rectangular block as a single cell, across columns, down rows, or
|
|
291
|
+
both. Coordinates are inclusive, zero-based, and ignore the index column.
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
table.merge_cells(0, 0, last_column=2, value='Quarter summary')
|
|
295
|
+
table.merge_cells(1, 0, last_row=3) # keeps the top-left content
|
|
296
|
+
table.merge_cells(0, 0, 2, 2, value='Total', align='r')
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
A merge never widens the table -- columns are still sized by their unmerged
|
|
300
|
+
content -- so text longer than its span is truncated.
|
|
301
|
+
|
|
302
|
+
# Performance
|
|
303
|
+
|
|
304
|
+
An optional C extension accelerates text measurement, and the render pipeline
|
|
305
|
+
avoids the second measuring pass when the table already fits. On identical
|
|
306
|
+
data:
|
|
307
|
+
|
|
308
|
+
| Library | 100x4 | 2000x4 | 10000x6 |
|
|
309
|
+
| --- | ---: | ---: | ---: |
|
|
310
|
+
| **flexablelib** | **1.0 ms** | **16.9 ms** | **147 ms** |
|
|
311
|
+
| prettytable | 1.4 ms | 23.2 ms | 174 ms |
|
|
312
|
+
| tabulate | 1.7 ms | 27.5 ms | 193 ms |
|
|
313
|
+
| pandas `.to_string()` | 1.7 ms | 22.9 ms | 228 ms |
|
|
314
|
+
|
|
315
|
+
Reproduce with `python3 tools/benchmark.py`. This measures one job: turning
|
|
316
|
+
data already in memory into formatted text. pandas is an analysis engine and
|
|
317
|
+
`to_string` is a convenience within it, so this says nothing about groupby or
|
|
318
|
+
joins.
|
|
319
|
+
|
|
320
|
+
The extension is built automatically where a compiler is available and falls
|
|
321
|
+
back to pure Python where it is not, so installation never fails for want of a
|
|
322
|
+
toolchain.
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
from flexablelib.fast import implementation
|
|
326
|
+
print(implementation()) # 'C extension' or 'pure Python'
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
# Known Issues
|
|
330
|
+
|
|
331
|
+
None of the three historical known issues remain:
|
|
332
|
+
|
|
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)).
|
|
339
|
+
|
|
340
|
+
Open work and the full issue map live in [docs/ISSUES.md](docs/ISSUES.md).
|
|
341
|
+
|
|
342
|
+
# Project Layout
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
prettyTables/ # GitHub repository (name unchanged)
|
|
346
|
+
├── flexablelib/ the Python package (no runtime dependencies)
|
|
347
|
+
│ ├── __init__.py public API: Table, TableComposition, SeparatorLine
|
|
348
|
+
│ ├── table.py the Table class — state and render orchestration
|
|
349
|
+
│ ├── columns.py type inference, alignment, column widths
|
|
350
|
+
│ ├── style_compositions.py the 42 border styles, as data
|
|
351
|
+
│ ├── table_strings.py separator lines and data rows
|
|
352
|
+
│ ├── cells.py cell padding, justification, wrapping
|
|
353
|
+
│ ├── options.py constants and defaults
|
|
354
|
+
│ └── utils.py type predicates and small helpers
|
|
355
|
+
├── tests/ pytest suite — see ARCHITECTURE.md#testing
|
|
356
|
+
├── docs/ issue history and design notes
|
|
357
|
+
├── logos/ brand assets — see logos/README.md
|
|
358
|
+
├── ARCHITECTURE.md how it all fits together
|
|
359
|
+
├── style_examples.md all 42 styles rendered
|
|
360
|
+
├── package.json canonical version number; drives the release
|
|
361
|
+
└── setup.py reads the version from package.json
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Run the tests from the repository root:
|
|
365
|
+
|
|
366
|
+
```
|
|
367
|
+
pip install -r requirements-dev.txt
|
|
368
|
+
python -m pytest
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
See [**ARCHITECTURE.md**](ARCHITECTURE.md) for the rendering pipeline, how styles are defined,
|
|
372
|
+
and how to add one.
|