This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 117f1151872 Show square brackets in airflowctl table and plain output
as typed (#76175)
117f1151872 is described below
commit 117f115187220b0dd9fa28573425893647a141c9
Author: Rishabh <[email protected]>
AuthorDate: Sun Nov 1 15:26:36 2026 +0530
Show square brackets in airflowctl table and plain output as typed (#76175)
* Show square brackets in airflowctl table and plain output as typed
`airflowctl ... --output table` and `--output plain` passed values to Rich
as markup, so a value such as `[/b]` crashed the command with a
MarkupError and a value such as `s3://[bucket]/path` silently lost its
bracketed part. Render the values literally, as `--output json` and
`--output yaml` already do.
* Show square brackets in airflowctl table headers as typed
Column headers were still passed to Rich as markup, so a key such as
`[/b]` raised a MarkupError and `[red]name[/red]` lost its tags in
`--output table`. Escape them like the cell values, and run the output
tests once per value, including a backslash before a tag.
---------
Co-authored-by: Shahar Epstein <[email protected]>
---
.../src/airflowctl/ctl/console_formatting.py | 7 +++---
.../airflow_ctl/ctl/test_console_formatting.py | 29 ++++++++++++++++++++++
2 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/airflow-ctl/src/airflowctl/ctl/console_formatting.py
b/airflow-ctl/src/airflowctl/ctl/console_formatting.py
index 38e06537516..20b4ad65e0c 100644
--- a/airflow-ctl/src/airflowctl/ctl/console_formatting.py
+++ b/airflow-ctl/src/airflowctl/ctl/console_formatting.py
@@ -23,6 +23,7 @@ from typing import TYPE_CHECKING, Any
from rich.box import ASCII_DOUBLE_HEAD
from rich.console import Console
+from rich.markup import escape
from rich.syntax import Syntax
from rich.table import Table
from tabulate import tabulate
@@ -74,10 +75,10 @@ class AirflowConsole(Console):
table = SimpleTable(show_header=self.show_header)
for col in data[0]:
- table.add_column(col)
+ table.add_column(escape(str(col)))
for row in data:
- table.add_row(*(str(d) for d in row.values()))
+ table.add_row(*(escape(str(d)) for d in row.values()))
self.print(table)
def print_as_plain_table(self, data: list[dict]):
@@ -87,7 +88,7 @@ class AirflowConsole(Console):
return
rows = [d.values() for d in data]
output = tabulate(rows, tablefmt="plain", headers=list(data[0]))
- self.print(output)
+ self.print(output, markup=False)
def _normalize_data(self, value: Any, output: str) -> list | str | dict |
None:
if isinstance(value, (tuple, list)):
diff --git a/airflow-ctl/tests/airflow_ctl/ctl/test_console_formatting.py
b/airflow-ctl/tests/airflow_ctl/ctl/test_console_formatting.py
index eca8e440c53..da48a224741 100644
--- a/airflow-ctl/tests/airflow_ctl/ctl/test_console_formatting.py
+++ b/airflow-ctl/tests/airflow_ctl/ctl/test_console_formatting.py
@@ -162,3 +162,32 @@ def test_simple_table_add_column_smoke():
table.add_column("column_1")
assert table.columns[0].header == "column_1"
+
+
+MARKUP_LIKE_TEXT = pytest.mark.parametrize(
+ "text",
+ ["s3://[bucket]/path", "[red]not styled[/red]", "a[0-9]+ [/b]",
r"path\[red]"],
+ ids=["unknown-tag", "style-tag", "closing-tag-only",
"backslash-before-tag"],
+)
+
+
[email protected]("output", ["table", "plain"])
+@MARKUP_LIKE_TEXT
+def test_print_as_keeps_square_brackets_in_values(output, text):
+ """Values that look like Rich markup are shown as-is instead of being
dropped or raising."""
+ console = console_formatting.AirflowConsole(record=True)
+
+ console.print_as([{"name": text}], output=output)
+
+ assert text in console.export_text()
+
+
[email protected]("output", ["table", "plain"])
+@MARKUP_LIKE_TEXT
+def test_print_as_keeps_square_brackets_in_headers(output, text):
+ """Column headers that look like Rich markup are shown as-is instead of
being dropped or raising."""
+ console = console_formatting.AirflowConsole(record=True)
+
+ console.print_as([{text: "value"}], output=output)
+
+ assert text in console.export_text()