From b1d5ff55a9ae13c32746f15257da9ef1e8b3c837 Mon Sep 17 00:00:00 2001 From: Pierre Camilleri Date: Mon, 27 Jul 2026 13:04:51 +0200 Subject: [PATCH 1/3] Use global Console() --- frictionless/console/commands/convert.py | 10 ++++------ frictionless/console/commands/describe.py | 12 +++++------- frictionless/console/commands/extract.py | 13 ++++++------- frictionless/console/commands/index.py | 10 ++++------ frictionless/console/commands/inspect.py | 8 +++----- frictionless/console/commands/list.py | 8 +++----- frictionless/console/commands/publish.py | 9 ++++----- frictionless/console/commands/query.py | 8 +++----- frictionless/console/commands/script.py | 8 +++----- frictionless/console/commands/validate.py | 11 +++++------ frictionless/console/helpers.py | 16 +++++++++------- 11 files changed, 49 insertions(+), 64 deletions(-) diff --git a/frictionless/console/commands/convert.py b/frictionless/console/commands/convert.py index 4f89e8df1e..663fb557a6 100644 --- a/frictionless/console/commands/convert.py +++ b/frictionless/console/commands/convert.py @@ -3,7 +3,6 @@ from typing import List import typer -from rich.console import Console from rich.progress import track from ...exception import FrictionlessException @@ -12,6 +11,7 @@ from ...system import system from .. import common, helpers from ..console import console +from ..helpers import output_console @console.command(name="convert") @@ -51,8 +51,6 @@ def console_convert( """ Convert data table """ - console = Console() - # Setup system if trusted: system.trusted = trusted @@ -115,7 +113,7 @@ def console_convert( raise FrictionlessException(note) # Convert resource - console.rule("[bold]Convert") + output_console.rule("[bold]Convert") # TODO: replace dummy progress bar a normal one for stage in track(["start", "end"], description="Converting..."): if stage == "end": @@ -128,5 +126,5 @@ def console_convert( raise typer.Exit(code=1) # Print result - console.rule("[bold]Result") - console.print(f"Succesefully converted to [bold]{to_path}[/bold]") + output_console.rule("[bold]Result") + output_console.print(f"Succesefully converted to [bold]{to_path}[/bold]") diff --git a/frictionless/console/commands/describe.py b/frictionless/console/commands/describe.py index e5582ea43f..8490bc9d65 100644 --- a/frictionless/console/commands/describe.py +++ b/frictionless/console/commands/describe.py @@ -3,7 +3,6 @@ from typing import List import typer -from rich.console import Console from rich.table import Table from ...dialect import Dialect @@ -14,6 +13,7 @@ from ...system import system from .. import common, helpers from ..console import console +from ..helpers import output_console DEFAULT_MAX_FIELDS = 10 @@ -64,8 +64,6 @@ def console_describe( Based on the inferred data source type it will return resource or package descriptor. Default output format is YAML with a front matter. """ - console = Console() - # Setup system if trusted: system.trusted = trusted @@ -137,7 +135,7 @@ def console_describe( raise typer.Exit() # Default mode - console.rule("[bold]Dataset") + output_console.rule("[bold]Dataset") assert isinstance(metadata, (Resource, Package)) resources = [metadata] if isinstance(metadata, Resource) else metadata.resources view = Table(title="dataset") @@ -158,8 +156,8 @@ def console_describe( row.append(str(resource.fields or "")) row.append(str(resource.rows or "")) view.add_row(*row, style=style) - console.print(view) - console.rule("[bold]Tables") + output_console.print(view) + output_console.rule("[bold]Tables") for resource in resources: if isinstance(resource, TableResource): view = Table(title=resource.name) @@ -172,4 +170,4 @@ def console_describe( if len(labels) > DEFAULT_MAX_FIELDS: row.append("...") view.add_row(*row) - console.print(view) + output_console.print(view) diff --git a/frictionless/console/commands/extract.py b/frictionless/console/commands/extract.py index 251a82c28c..8c9b523c19 100644 --- a/frictionless/console/commands/extract.py +++ b/frictionless/console/commands/extract.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, List, Optional import typer -from rich.console import Console from rich.table import Table from ...exception import FrictionlessException @@ -14,6 +13,7 @@ from ...system import system from .. import common, helpers from ..console import console +from ..helpers import output_console if TYPE_CHECKING: from ... import types @@ -77,7 +77,6 @@ def console_extract( Based on the inferred data source type it will return resource or package data. Default output format is tabulated with a front matter. Output will be utf-8 encoded. """ - console = Console() name = name or resource_name # Setup system @@ -215,7 +214,7 @@ def console_extract( raise typer.Exit() # Default mode - console.rule("[bold]Dataset") + output_console.rule("[bold]Dataset") view = Table(title="dataset") view.add_column("name") view.add_column("type") @@ -224,13 +223,13 @@ def console_extract( style = "sky_blue1" if resource.tabular else "" row = [resource.name, resource.type, resource.path] view.add_row(*row, style=style) - console.print(view) + output_console.print(view) - console.rule("[bold]Tables") + output_console.rule("[bold]Tables") for title, items in data.items(): # Empty if not items: - helpers.print_panel(console, note="No rows found", title="Empty") + helpers.print_panel(note="No rows found", title="Empty") continue # General @@ -252,4 +251,4 @@ def console_extract( if len(labels) > DEFAULT_MAX_FIELDS: row.append("...") view.add_row(*row) - console.print(view) + output_console.print(view) diff --git a/frictionless/console/commands/index.py b/frictionless/console/commands/index.py index 5be65e31ef..7167af65f0 100644 --- a/frictionless/console/commands/index.py +++ b/frictionless/console/commands/index.py @@ -3,12 +3,12 @@ from typing import List import typer -from rich.console import Console from ...resource import Resource from ...system import system from .. import common, helpers from ..console import console +from ..helpers import output_console @console.command(name="index") @@ -29,7 +29,6 @@ def console_index( standards: str = common.standards, ): """Index a tabular data resource""" - console = Console() # Setup system if trusted: @@ -45,7 +44,7 @@ def console_index( raise typer.Exit(code=1) # Index resource - console.rule("[bold]Index") + output_console.rule("[bold]Index") try: # Create resource resource = Resource( @@ -61,7 +60,6 @@ def console_index( for resource in resources: names.extend( helpers.index_resource( - console, resource=resource, database=database, fast=fast, @@ -75,5 +73,5 @@ def console_index( raise typer.Exit(code=1) # Print result - console.rule("[bold]Result") - console.print(f"Succesefully indexed [bold]{len(names)}[/] tables") + output_console.rule("[bold]Result") + output_console.print(f"Succesefully indexed [bold]{len(names)}[/] tables") diff --git a/frictionless/console/commands/inspect.py b/frictionless/console/commands/inspect.py index 43e5b3f2d2..190e228d2e 100644 --- a/frictionless/console/commands/inspect.py +++ b/frictionless/console/commands/inspect.py @@ -6,12 +6,12 @@ from typing import List import typer -from rich.console import Console from ...resource import Resource from ...system import system from .. import common, helpers from ..console import console +from ..helpers import output_console # TODO: figure out how we can reduce duplication among commands like this: query/etc @@ -28,7 +28,6 @@ def console_inspect( standards: str = common.standards, ): """Query data""" - console = Console() # Setup system if trusted: @@ -44,7 +43,7 @@ def console_inspect( raise typer.Exit(code=1) # Index resource - console.rule("[bold]Index") + output_console.rule("[bold]Index") try: # Create resource resource = Resource( @@ -65,7 +64,6 @@ def console_inspect( for resource in resources: names.extend( helpers.index_resource( - console, resource=resource, database=database, fast=True, @@ -84,5 +82,5 @@ def console_inspect( raise typer.Exit(1) # Enter database - console.rule("[bold]Inspect") + output_console.rule("[bold]Inspect") os.system(f"datasette {database}") diff --git a/frictionless/console/commands/list.py b/frictionless/console/commands/list.py index 2b7dcac679..2dc7993daa 100644 --- a/frictionless/console/commands/list.py +++ b/frictionless/console/commands/list.py @@ -3,7 +3,6 @@ from typing import List import typer -from rich.console import Console from rich.table import Table from ...helpers import to_json, to_yaml @@ -11,6 +10,7 @@ from ...system import system from .. import common, helpers from ..console import console +from ..helpers import output_console @console.command(name="list") @@ -55,8 +55,6 @@ def console_describe( """ List a data source. """ - console = Console() - # Setup system if trusted: system.trusted = trusted @@ -133,7 +131,7 @@ def console_describe( raise typer.Exit() # Default mode - console.rule("[bold]Dataset") + output_console.rule("[bold]Dataset") view = Table(title="dataset") view.add_column("name") view.add_column("type") @@ -142,4 +140,4 @@ def console_describe( style = "sky_blue1" if resource.tabular else "" row = [resource.name, resource.type, resource.path] view.add_row(*row, style=style) - console.print(view) + output_console.print(view) diff --git a/frictionless/console/commands/publish.py b/frictionless/console/commands/publish.py index 221aad0ebd..199ba58e11 100644 --- a/frictionless/console/commands/publish.py +++ b/frictionless/console/commands/publish.py @@ -3,7 +3,6 @@ from typing import List import typer -from rich.console import Console from rich.progress import track from rich.prompt import Prompt @@ -14,6 +13,7 @@ from ...system import system from .. import common, helpers from ..console import console +from ..helpers import output_console @console.command(name="publish") @@ -32,7 +32,6 @@ def console_publish( standards: str = common.standards, ): """Script data""" - console = Console() portals = platform.frictionless_portals # Setup system @@ -60,7 +59,7 @@ def console_publish( package = Package(title=title, resources=resources) # Publish package - console.rule("[bold]Publish") + output_console.rule("[bold]Publish") adapter = system.create_adapter(target, packagify=True) if not isinstance(adapter, portals.ckan.CkanAdapter): raise FrictionlessException("Currently only CKAN publishing is supported") @@ -75,5 +74,5 @@ def console_publish( raise typer.Exit(code=1) # Print result - console.rule("[bold]Result") - console.print(f"Succesefully published to [bold]{target}[/bold]") + output_console.rule("[bold]Result") + output_console.print(f"Succesefully published to [bold]{target}[/bold]") diff --git a/frictionless/console/commands/query.py b/frictionless/console/commands/query.py index 389cda3701..6733c1ca9c 100644 --- a/frictionless/console/commands/query.py +++ b/frictionless/console/commands/query.py @@ -6,12 +6,12 @@ from typing import List import typer -from rich.console import Console from ...resource import Resource from ...system import system from .. import common, helpers from ..console import console +from ..helpers import output_console @console.command(name="query") @@ -27,7 +27,6 @@ def console_query( standards: str = common.standards, ): """Query data""" - console = Console() # Setup system if trusted: @@ -43,7 +42,7 @@ def console_query( raise typer.Exit(code=1) # Index resource - console.rule("[bold]Index") + output_console.rule("[bold]Index") try: # Create resource resource = Resource( @@ -64,7 +63,6 @@ def console_query( for resource in resources: names.extend( helpers.index_resource( - console, resource=resource, database=database, fast=True, @@ -83,5 +81,5 @@ def console_query( raise typer.Exit(1) # Enter database - console.rule("[bold]Query") + output_console.rule("[bold]Query") os.system(f"sqlite3 {database}") diff --git a/frictionless/console/commands/script.py b/frictionless/console/commands/script.py index 66c91a5393..823e57211a 100644 --- a/frictionless/console/commands/script.py +++ b/frictionless/console/commands/script.py @@ -7,13 +7,13 @@ from typing import List import typer -from rich.console import Console from ...helpers import write_file from ...resource import Resource from ...system import system from .. import common, helpers from ..console import console +from ..helpers import output_console @console.command(name="script") @@ -29,7 +29,6 @@ def console_script( standards: str = common.standards, ): """Script data""" - console = Console() # Setup system if trusted: @@ -45,7 +44,7 @@ def console_script( raise typer.Exit(code=1) # Index resource - console.rule("[bold]Index") + output_console.rule("[bold]Index") try: # Create resource resource = Resource( @@ -66,7 +65,6 @@ def console_script( for resource in resources: names.extend( helpers.index_resource( - console, resource=resource, database=database, fast=True, @@ -85,7 +83,7 @@ def console_script( raise typer.Exit(1) # Enter interpreter - console.rule("[bold]Script") + output_console.rule("[bold]Script") file = tempfile.NamedTemporaryFile(delete=False, suffix=".py") atexit.register(os.remove, file.name) startup = generate_startup(database, names=names) diff --git a/frictionless/console/commands/validate.py b/frictionless/console/commands/validate.py index 74f1cac040..41d5cbc7f9 100644 --- a/frictionless/console/commands/validate.py +++ b/frictionless/console/commands/validate.py @@ -3,13 +3,13 @@ from typing import List import typer -from rich.console import Console from rich.table import Table from ...resource import Resource from ...system import system from .. import common, helpers from ..console import console +from ..helpers import output_console @console.command(name="validate") @@ -72,7 +72,6 @@ def console_validate( Based on the inferred data source type it will validate resource or package. Default output format is YAML with a front matter. """ - console = Console() name = name or resource_name # Setup system @@ -179,7 +178,7 @@ def console_validate( # Status if report.tasks: - console.rule("[bold]Dataset") + output_console.rule("[bold]Dataset") view = Table(title="dataset") view.add_column("name") view.add_column("type") @@ -190,11 +189,11 @@ def console_validate( style = "green" if task.valid else "bold red" status_row = [task.name, task.type, task.place, status] view.add_row(*status_row, style=style) - console.print(view) + output_console.print(view) # Errors if not report.valid: - console.rule("[bold]Tables") + output_console.rule("[bold]Tables") for name, errors in zip(names, matrix): if errors: view = Table(title=name) @@ -205,7 +204,7 @@ def console_validate( for prop in props: error_row.append(str(getattr(error, prop, None))) view.add_row(*error_row) - console.print(view) + output_console.print(view) # Proper retcode raise typer.Exit(code=code) diff --git a/frictionless/console/helpers.py b/frictionless/console/helpers.py index dc29a47723..65c363b30c 100644 --- a/frictionless/console/helpers.py +++ b/frictionless/console/helpers.py @@ -202,7 +202,6 @@ def create_pipeline( def index_resource( - console: Console, *, resource: Resource, database: str, @@ -241,30 +240,33 @@ def index_resource( use_fallback=use_fallback, qsv_path=qsv_path, ) - console.print(f"{progress.tasks[status].description} in {timer.time} seconds") + output_console.print( + f"{progress.tasks[status].description} in {timer.time} seconds" + ) return names except Exception as exception: if debug: print_exception(exception=exception, debug=debug) raise typer.Exit(code=1) - console.print(f"\\[{resource.name}] errored") + output_console.print(f"\\[{resource.name}] errored") return [] # Console +output_console = Console() error_console = Console(stderr=True) -def print_success(console: Console, *, note: str, title: str = "Success") -> None: +def print_success(*, note: str, title: str = "Success") -> None: panel = Panel(note, title=title, border_style="green", title_align="left") - console.print(panel) + output_console.print(panel) -def print_panel(console: Console, *, note: str, title: str) -> None: +def print_panel(*, note: str, title: str) -> None: panel = Panel(note, title=title, title_align="left") - console.print(panel) + output_console.print(panel) def print_error(*, note: str, title: str = "Error") -> None: From 730a2ee05c83ec02d55937052d905d4a5db03062 Mon Sep 17 00:00:00 2001 From: Pierre Camilleri Date: Mon, 27 Jul 2026 13:08:01 +0200 Subject: [PATCH 2/3] Factorize helpers --- frictionless/console/helpers.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frictionless/console/helpers.py b/frictionless/console/helpers.py index 65c363b30c..d55d3d55f7 100644 --- a/frictionless/console/helpers.py +++ b/frictionless/console/helpers.py @@ -282,6 +282,4 @@ def print_exception( if debug: error_console.print_exception() return - text = escape(str(exception)) - panel = Panel(text, title="Error", border_style="red", title_align="left") - error_console.print(panel) + print_error(note=escape(str(exception))) From 22dd34df98b39bdec9cf3b8bd73c33d15fe75ca0 Mon Sep 17 00:00:00 2001 From: Pierre Camilleri Date: Mon, 27 Jul 2026 13:08:45 +0200 Subject: [PATCH 3/3] Remove dead code --- frictionless/console/helpers.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frictionless/console/helpers.py b/frictionless/console/helpers.py index d55d3d55f7..386233ce0e 100644 --- a/frictionless/console/helpers.py +++ b/frictionless/console/helpers.py @@ -259,11 +259,6 @@ def index_resource( error_console = Console(stderr=True) -def print_success(*, note: str, title: str = "Success") -> None: - panel = Panel(note, title=title, border_style="green", title_align="left") - output_console.print(panel) - - def print_panel(*, note: str, title: str) -> None: panel = Panel(note, title=title, title_align="left") output_console.print(panel)