turbaszek commented on a change in pull request #12704:
URL: https://github.com/apache/airflow/pull/12704#discussion_r532868322
##########
File path: airflow/cli/commands/connection_command.py
##########
@@ -19,78 +19,54 @@
import json
import os
import sys
-from typing import List
+from typing import Any, Dict, List
from urllib.parse import urlparse, urlunparse
-import pygments
import yaml
-from pygments.lexers.data import YamlLexer
from sqlalchemy.orm import exc
-from tabulate import tabulate
+from airflow.cli.simple_table import AirflowConsole
from airflow.exceptions import AirflowNotFoundException
from airflow.hooks.base_hook import BaseHook
from airflow.models import Connection
from airflow.utils import cli as cli_utils
-from airflow.utils.cli import should_use_colors
-from airflow.utils.code_utils import get_terminal_formatter
+from airflow.utils.cli import suppress_logs_and_warning
from airflow.utils.session import create_session
-def _tabulate_connection(conns: List[Connection], tablefmt: str):
- tabulate_data = [
- {
- 'Conn Id': conn.conn_id,
- 'Conn Type': conn.conn_type,
- 'Description': conn.description,
- 'Host': conn.host,
- 'Port': conn.port,
- 'Is Encrypted': conn.is_encrypted,
- 'Is Extra Encrypted': conn.is_encrypted,
- 'Extra': conn.extra,
- }
- for conn in conns
- ]
-
- msg = tabulate(tabulate_data, tablefmt=tablefmt, headers='keys')
- return msg
-
-
-def _yamulate_connection(conn: Connection):
- yaml_data = {
- 'Id': conn.id,
- 'Conn Id': conn.conn_id,
- 'Conn Type': conn.conn_type,
- 'Description': conn.description,
- 'Host': conn.host,
- 'Schema': conn.schema,
- 'Login': conn.login,
- 'Password': conn.password,
- 'Port': conn.port,
- 'Is Encrypted': conn.is_encrypted,
- 'Is Extra Encrypted': conn.is_encrypted,
- 'Extra': conn.extra_dejson,
- 'URI': conn.get_uri(),
+def _connection_mapper(conn: Connection) -> Dict[str, Any]:
+ return {
+ 'id': conn.id,
+ 'conn_id': conn.conn_id,
+ 'conn_type': conn.conn_type,
+ 'description': conn.description,
+ 'host': conn.host,
+ 'schema': conn.schema,
+ 'login': conn.login,
+ 'password': conn.password,
+ 'port': conn.port,
+ 'is_encrypted': conn.is_encrypted,
+ 'is_extra_encrypted': conn.is_encrypted,
+ 'extra_dejson': conn.extra_dejson,
+ 'get_uri()': conn.get_uri(),
Review comment:
Done in caf81ff
##########
File path: UPDATING.md
##########
@@ -52,6 +52,39 @@ assists users migrating to a new version.
## Master
+### Changes to output argument in commands
+
+Instead of using [tabulate](https://pypi.org/project/tabulate/) to render
commands output
+we use [rich](https://github.com/willmcgugan/rich). Due to this change the
`--output` argument
+will no longer accept formats of tabulate tables. Instead it accepts:
+
+- `table` - will render the output in predefined table
+- `json` - will render the output as a json
+- `yaml` - will render the output as yaml
+
+By doing this we increased consistency and gave users possibility to
manipulate the
+output programmatically (when using json or yaml).
+
+Affected commands:
+
+- `airflow dags list`
+- `airflow dags report`
+- `airflow dags list-runs`
+- `airflow dags list-jobs`
+- `airflow connections list`
+- `airflow connections get`
+- `airflow pools list`
+- `airflow pools get`
+- `airflow pools set`
+- `airflow pools delete`
+- `airflow pools export`
+- `airflow role list`
+- `airflow providers list`
+- `airflow providers get`
+- `airflow tasks states-for-dag-run`
+- `airflow users list`
+- `airflow variables list`
Review comment:
Done in caf81ff
##########
File path: docs/usage-cli.rst
##########
@@ -174,3 +174,40 @@ You will see a similar result as in the screenshot below.
.. figure:: img/usage_cli_imgcat.png
Preview of DAG in iTerm2
+
+Formatting commands output
+--------------------------
+
+Some Airflow commands like ``dags list`` or ``tasks states-for-dag-run``
support ``--output`` flag which allow users
Review comment:
Done in caf81ff
##########
File path: airflow/cli/simple_table.py
##########
@@ -14,11 +14,78 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
+import json
+from typing import Any, Callable, Dict, List, Optional, Union
+import yaml
from rich.box import ASCII_DOUBLE_HEAD
+from rich.console import Console
+from rich.syntax import Syntax
from rich.table import Table
+class AirflowConsole(Console):
+ """Airflow rich console"""
+
+ def print_as_json(self, data: Dict):
+ """Renders dict as json text representation"""
+ json_content = json.dumps(data)
+ self.print(Syntax(json_content, "json", theme="ansi_dark"),
soft_wrap=True)
+
+ def print_as_yaml(self, data: Dict):
+ """Renders dict as yaml text representation"""
+ yaml_content = yaml.dump(data)
+ self.print(Syntax(yaml_content, "yaml", theme="ansi_dark"),
soft_wrap=True)
+
+ def print_as_table(self, data: List[Dict]):
+ """Renders list of dictionaries as table"""
+ if not data:
+ self.print("No data found")
+ return
+
+ table = SimpleTable(
+ show_header=True,
+ )
+ for col in data[0].keys():
+ table.add_column(col)
+
+ for row in data:
+ table.add_row(*[str(d) for d in row.values()])
+ self.print(table)
+
+ def _normalize_data(self, value: Any, output: str) -> Union[list, str,
dict]:
+ if isinstance(value, (tuple, list)):
+ if output == "table":
+ return ",".join(self._normalize_data(x, output) for x in value)
+ return [self._normalize_data(x, output) for x in value]
+ if isinstance(value, dict) and output != "table":
+ return {k: self._normalize_data(v, output) for k, v in
value.items()}
+ return str(value)
+
+ def print_as(self, data: List[Union[Dict, Any]], output: str, mapper:
Optional[Callable] = None):
+ """Prints provided using format specified by output argument"""
+ output_to_renderer = {
+ "json": self.print_as_json,
+ "yaml": self.print_as_yaml,
+ "table": self.print_as_table,
+ }
+ renderer = output_to_renderer.get(output)
+ if not renderer:
+ raise ValueError(
+ f"Unknown formatter: {output}. Allowed options:
{list(output_to_renderer.keys())}"
+ )
+
+ if not all(isinstance(d, dict) for d in data) and not mapper:
+ raise ValueError("To tabulate non-dictionary data you need to
provider `mapper` function")
Review comment:
Done in caf81ff
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]