From 6f804e9636499f2c37154192e8d60c47670403cc Mon Sep 17 00:00:00 2001 From: Roland Walker Date: Sat, 26 Jul 2025 08:59:25 -0400 Subject: [PATCH] add mysql/mysql_unicode output formats The difference being that for the mysql formats, numbers are right aligned. Addresses https://github.com/dbcli/mycli/issues/1102 . --- CHANGELOG | 10 +++ .../tabular_output/tabulate_adapter.py | 28 ++++++++ tests/tabular_output/test_output_formatter.py | 72 +++++++++++++++++++ 3 files changed, 110 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index bfdd299..0ed7bee 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,12 +1,22 @@ # Changelog +## Version 2.7.0 + +(released on 2025-07-28) + +- Add `mysql` and `mysql_unicode` output formats which right-align numbers. + ## Version 2.6.0 +(released on 2025-07-12) + - Register the JSON formats so they are actually usable. - Make JSON formats able to encode Decimals and None/NULLs. ## Version 2.5.0 +(released on 2025-07-10) + - Added noheader CSV and TSV output formats. - Added `jsonl` and `jsonl_escaped` output formats. diff --git a/cli_helpers/tabular_output/tabulate_adapter.py b/cli_helpers/tabular_output/tabulate_adapter.py index 2c557f8..f175f20 100644 --- a/cli_helpers/tabular_output/tabulate_adapter.py +++ b/cli_helpers/tabular_output/tabulate_adapter.py @@ -63,6 +63,28 @@ with_header_hide=None, ) +tabulate._table_formats["mysql"] = tabulate.TableFormat( + lineabove=tabulate.Line("+", "-", "+", "+"), + linebelowheader=tabulate.Line("+", "-", "+", "+"), + linebetweenrows=None, + linebelow=tabulate.Line("+", "-", "+", "+"), + headerrow=tabulate.DataRow("|", "|", "|"), + datarow=tabulate.DataRow("|", "|", "|"), + padding=1, + with_header_hide=None, +) + +tabulate._table_formats["mysql_unicode"] = tabulate.TableFormat( + lineabove=tabulate.Line("┌", "─", "┬", "┐"), + linebelowheader=tabulate.Line("├", "─", "┼", "┤"), + linebetweenrows=None, + linebelow=tabulate.Line("└", "─", "┴", "┘"), + headerrow=tabulate.DataRow("│", "│", "│"), + datarow=tabulate.DataRow("│", "│", "│"), + padding=1, + with_header_hide=None, +) + # "minimal" is the same as "plain", but without headers tabulate._table_formats["minimal"] = tabulate._table_formats["plain"] @@ -70,6 +92,8 @@ tabulate.multiline_formats["double"] = "double" tabulate.multiline_formats["ascii"] = "ascii" tabulate.multiline_formats["minimal"] = "minimal" +tabulate.multiline_formats["mysql"] = "mysql" +tabulate.multiline_formats["mysql_unicode"] = "mysql_unicode" supported_markup_formats = ( "mediawiki", @@ -95,6 +119,8 @@ "rst", "github", "double", + "mysql", + "mysql_unicode", ) supported_formats = supported_markup_formats + supported_table_formats @@ -102,6 +128,8 @@ default_kwargs = { "ascii": {"numalign": "left"}, "ascii_escaped": {"numalign": "left"}, + "mysql": {"numalign": "right"}, + "mysql_unicode": {"numalign": "right"}, } headless_formats = ("minimal",) diff --git a/tests/tabular_output/test_output_formatter.py b/tests/tabular_output/test_output_formatter.py index a76ca7c..4bce9e4 100644 --- a/tests/tabular_output/test_output_formatter.py +++ b/tests/tabular_output/test_output_formatter.py @@ -83,6 +83,78 @@ def test_tabular_output_escaped(): ) +def test_tabular_output_mysql(): + """Test the mysql output format.""" + headers = ["text", "numeric"] + data = [ + ["abc", Decimal(1)], + ["defg", Decimal("11.1")], + ["hi", Decimal("1.1")], + ["Pablo\rß\n", 0], + ] + expected = dedent( + """\ + +-------+---------+ + | text | numeric | + +-------+---------+ + | abc | 1 | + | defg | 11.1 | + | hi | 1.1 | + | Pablo | 0 | + | ß | | + +-------+---------+""" + ) + + print(expected) + print( + "\n".join( + TabularOutputFormatter().format_output( + iter(data), headers, format_name="mysql" + ) + ) + ) + assert expected == "\n".join( + TabularOutputFormatter().format_output(iter(data), headers, format_name="mysql") + ) + + +def test_tabular_output_mysql_unicode(): + """Test the mysql_unicode output format.""" + headers = ["text", "numeric"] + data = [ + ["abc", Decimal(1)], + ["defg", Decimal("11.1")], + ["hi", Decimal("1.1")], + ["Pablo\rß\n", 0], + ] + expected = dedent( + """\ + ┌───────┬─────────┐ + │ text │ numeric │ + ├───────┼─────────┤ + │ abc │ 1 │ + │ defg │ 11.1 │ + │ hi │ 1.1 │ + │ Pablo │ 0 │ + │ ß │ │ + └───────┴─────────┘""" + ) + + print(expected) + print( + "\n".join( + TabularOutputFormatter().format_output( + iter(data), headers, format_name="mysql_unicode" + ) + ) + ) + assert expected == "\n".join( + TabularOutputFormatter().format_output( + iter(data), headers, format_name="mysql_unicode" + ) + ) + + def test_tabular_format_output_wrapper(): """Test the format_output wrapper.""" data = [["1", None], ["2", "Sam"], ["3", "Joe"]]