From 8e8043d862fc8f4bd9d6265d6f6fa404fec46399 Mon Sep 17 00:00:00 2001 From: leonace924 Date: Mon, 22 Dec 2025 20:32:34 -0500 Subject: [PATCH 1/6] feat: add the resuable create_table for subnets --- bittensor_cli/src/bittensor/utils.py | 58 +++++++++++++++++ bittensor_cli/src/commands/subnets/subnets.py | 63 +++---------------- 2 files changed, 65 insertions(+), 56 deletions(-) diff --git a/bittensor_cli/src/bittensor/utils.py b/bittensor_cli/src/bittensor/utils.py index d6375927..26bd49e2 100644 --- a/bittensor_cli/src/bittensor/utils.py +++ b/bittensor_cli/src/bittensor/utils.py @@ -25,6 +25,7 @@ from numpy.typing import NDArray from rich.console import Console from rich.prompt import Confirm, Prompt +from rich.table import Table from scalecodec import GenericCall from scalecodec.utils.ss58 import ss58_encode, ss58_decode import typer @@ -89,6 +90,63 @@ def confirm_action( return Confirm.ask(message, default=default) +def create_table(*columns, title: str = "", **overrides) -> Table: + """ + Creates a Rich Table with consistent CLI styling. + + Default styling: no edge borders, bold white headers, bright black borders, + footer enabled, center-aligned title, and no lines between rows. + + Args: + *columns: Optional Column objects to add to the table upfront. + title: Table title with rich markup support. + **overrides: Any Table() parameter to override defaults (e.g., show_footer, + border_style, box, expand). + + Returns: + Configured Rich Table ready for adding columns/rows. + + Examples: + Basic usage (add columns later): + >>> table = create_table(title="My Subnets") + >>> table.add_column("Netuid", justify="center") + >>> table.add_row("1") + + With Column objects upfront: + >>> from rich.table import Column + >>> table = create_table( + ... Column("Name", justify="left"), + ... Column("Value", justify="right"), + ... title="Settings" + ... ) + >>> table.add_row("Timeout", "30s") + + Custom styling: + >>> from rich import box + >>> table = create_table( + ... title="Custom", + ... border_style="blue", + ... box=box.ROUNDED + ... ) + """ + defaults = { + "title": title, + "show_footer": True, + "show_edge": False, + "header_style": "bold white", + "border_style": "bright_black", + "style": "bold", + "title_justify": "center", + "show_lines": False, + "pad_edge": True, + } + + # Merge overrides into defaults + config = {**defaults, **overrides} + + return Table(*columns, **config) + + jinja_env = Environment( loader=PackageLoader("bittensor_cli", "src/bittensor/templates"), autoescape=select_autoescape(), diff --git a/bittensor_cli/src/commands/subnets/subnets.py b/bittensor_cli/src/commands/subnets/subnets.py index 610606ba..ece49f57 100644 --- a/bittensor_cli/src/commands/subnets/subnets.py +++ b/bittensor_cli/src/commands/subnets/subnets.py @@ -30,6 +30,7 @@ confirm_action, console, create_and_populate_table, + create_table, print_success, print_verbose, print_error, @@ -364,17 +365,9 @@ def define_table( tao_emission_percentage: str, total_tao_flow_ema: float, ): - defined_table = Table( + defined_table = create_table( title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Subnets" f"\nNetwork: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{subtensor.network}\n\n", - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) defined_table.add_column( @@ -1095,17 +1088,9 @@ async def show_root(): tao_sum = sum(root_state.tao_stake).tao - table = Table( + table = create_table( title=f"[{COLOR_PALETTE.G.HEADER}]Root Network\n[{COLOR_PALETTE.G.SUBHEAD}]" f"Network: {subtensor.network}[/{COLOR_PALETTE.G.SUBHEAD}]\n", - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) table.add_column("[bold white]Position", style="white", justify="center") @@ -1340,18 +1325,10 @@ async def show_subnet( # Define table properties mechanism_label = f"Mechanism {selected_mechanism_id}" - table = Table( + table = create_table( title=f"[{COLOR_PALETTE['GENERAL']['HEADER']}]Subnet [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{netuid_}" f"{': ' + get_subnet_name(subnet_info)}" f"\n[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]Network: {subtensor.network} • {mechanism_label}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]\n", - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) # For table footers @@ -1892,22 +1869,13 @@ async def _storage_key(storage_fn: str) -> StorageKey: return if prompt and not json_output: - # TODO make this a reusable function, also used in subnets list # Show creation table. - table = Table( + table = create_table( title=( f"\n[{COLOR_PALETTE.G.HEADER}]" f"Register to [{COLOR_PALETTE.G.SUBHEAD}]netuid: {netuid}[/{COLOR_PALETTE.G.SUBHEAD}]" f"\nNetwork: [{COLOR_PALETTE.G.SUBHEAD}]{subtensor.network}[/{COLOR_PALETTE.G.SUBHEAD}]\n" ), - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) table.add_column( "Netuid", style="rgb(253,246,227)", no_wrap=True, justify="center" @@ -2476,16 +2444,8 @@ async def metagraph_cmd( table_cols_indices.append(idx) table_cols.append(v) - table = Table( + table = create_table( *table_cols, - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_style="bold white", - title_justify="center", - show_lines=False, expand=True, title=( f"[underline dark_orange]Metagraph[/underline dark_orange]\n\n" @@ -2496,7 +2456,6 @@ async def metagraph_cmd( f"Issuance: [bright_blue]{metadata_info['issuance']}[/bright_blue], " f"Difficulty: [bright_cyan]{metadata_info['difficulty']}[/bright_cyan]\n" ), - pad_edge=True, ) if all(x is False for x in display_cols.values()): @@ -2521,7 +2480,7 @@ def create_identity_table(title: str = None): if not title: title = "Subnet Identity" - table = Table( + table = create_table( Column( "Item", justify="right", @@ -2530,14 +2489,6 @@ def create_identity_table(title: str = None): ), Column("Value", style=COLOR_PALETTE["GENERAL"]["SUBHEADING"]), title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]{title}\n", - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) return table From 123de68090a5a91b89b642ce454b5969b90bd1c5 Mon Sep 17 00:00:00 2001 From: leonace924 Date: Mon, 22 Dec 2025 20:32:43 -0500 Subject: [PATCH 2/6] feat: add create table unit test --- tests/unit_tests/test_utils.py | 171 +++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/tests/unit_tests/test_utils.py b/tests/unit_tests/test_utils.py index 6a3774d0..22e4135d 100644 --- a/tests/unit_tests/test_utils.py +++ b/tests/unit_tests/test_utils.py @@ -5,7 +5,10 @@ from bittensor_cli.src.bittensor.utils import ( check_img_mimetype, confirm_action, + create_table, ) +from rich.table import Column, Table +from bittensor_cli.src import COLOR_PALETTE @pytest.mark.parametrize( @@ -131,3 +134,171 @@ def test_confirm_action_default_values(self): result = confirm_action("Do you want to proceed?") assert result is True mock_ask.assert_called_once() + + +class TestCreateTable: + """Tests for the create_table utility function.""" + + def test_simple_table_creation(self): + """Test creating a simple table with default styling.""" + table = create_table(title="My Subnets") + + # Verify it returns a Table instance + assert isinstance(table, Table) + assert table.title == "My Subnets" + + # Verify default styling is applied + assert table.show_footer is True + assert table.show_edge is False + assert table.header_style == "bold white" + assert table.border_style == "bright_black" + assert table.title_justify == "center" + assert table.show_lines is False + assert table.pad_edge is True + + def test_table_with_columns_added_later(self): + """Test adding columns after table creation.""" + table = create_table(title="Test Table") + + # Add columns dynamically + table.add_column("Column1", justify="center") + table.add_column("Column2", justify="left") + + assert len(table.columns) == 2 + assert table.columns[0].header == "Column1" + assert table.columns[1].header == "Column2" + + # Add rows + table.add_row("Value1", "Value2") + assert len(table.rows) == 1 + + def test_table_with_column_objects(self): + """Test creating table with Column objects upfront (identity table pattern).""" + table = create_table( + Column( + "Item", + justify="right", + style=COLOR_PALETTE["GENERAL"]["SUBHEADING_MAIN"], + no_wrap=True, + ), + Column("Value", style=COLOR_PALETTE["GENERAL"]["SUBHEADING"]), + title="Identity", + ) + + # Verify columns were added + assert len(table.columns) == 2 + assert table.columns[0].header == "Item" + assert table.columns[1].header == "Value" + assert table.columns[0].justify == "right" + assert table.columns[0].no_wrap is True + + # Verify default styling still applied + assert table.show_footer is True + assert table.show_edge is False + + def test_custom_overrides(self): + """Test overriding default parameters.""" + table = create_table( + title="Custom Table", + show_footer=False, + border_style="blue", + show_lines=True, + ) + + # Verify overrides applied + assert table.show_footer is False + assert table.border_style == "blue" + assert table.show_lines is True + + # Verify non-overridden defaults preserved + assert table.show_edge is False + assert table.header_style == "bold white" + + def test_subnets_list_pattern(self): + """Test actual pattern from subnets_list() function.""" + table = create_table( + title=f"[{COLOR_PALETTE['GENERAL']['HEADER']}]Subnets\n" + f"Network: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]finney\n", + ) + + # Add columns as in actual code + table.add_column("[bold white]Netuid", style="grey89", justify="center") + table.add_column("[bold white]Name", style="cyan", justify="left") + table.add_column("[bold white]Price", style="dark_sea_green2", justify="left") + + assert len(table.columns) == 3 + + # Add sample row + table.add_row("1", "Alpha", "0.0025") + assert len(table.rows) == 1 + + def test_registration_pattern(self): + """Test registration confirmation table pattern.""" + table = create_table( + title=( + f"[{COLOR_PALETTE.G.HEADER}]" + f"Register to [{COLOR_PALETTE.G.SUBHEAD}]netuid: 1[/{COLOR_PALETTE.G.SUBHEAD}]\n" + f"Network: [{COLOR_PALETTE.G.SUBHEAD}]finney[/{COLOR_PALETTE.G.SUBHEAD}]\n" + ), + ) + + table.add_column("Netuid", style="rgb(253,246,227)", no_wrap=True, justify="center") + table.add_column("Symbol", style=COLOR_PALETTE["GENERAL"]["SYMBOL"], no_wrap=True) + table.add_column("Cost (τ)", style=COLOR_PALETTE["POOLS"]["TAO"], justify="center") + + assert len(table.columns) == 3 + + # Add sample row + table.add_row("1", "α", "τ 0.5000") + assert len(table.rows) == 1 + + def test_advanced_rich_features(self): + """Test advanced Rich features with custom box and expand.""" + from rich import box + + table = create_table( + Column("Command", overflow="fold", ratio=2), + Column("Description", overflow="fold", ratio=3), + title="Commands", + box=box.ROUNDED, + expand=True, + padding=(0, 1), + ) + + assert table.box == box.ROUNDED + assert table.expand is True + assert len(table.columns) == 2 + assert table.columns[0].ratio == 2 + assert table.columns[1].ratio == 3 + + def test_empty_table_minimal_config(self): + """Test creating empty table with minimal configuration.""" + table = create_table() + + assert isinstance(table, Table) + assert table.title == "" + assert table.show_footer is True + assert len(table.columns) == 0 + + def test_multiple_column_objects_with_styling(self): + """Test multiple Column objects with various styling options.""" + table = create_table( + Column("Col1", style="cyan", justify="left"), + Column("Col2", style="green", justify="center", no_wrap=True), + Column("Col3", style="yellow", justify="right", overflow="fold"), + title="Multi-Column Test", + ) + + assert len(table.columns) == 3 + assert table.columns[0].style == "cyan" + assert table.columns[1].justify == "center" + assert table.columns[2].overflow == "fold" + + def test_rich_markup_in_title(self): + """Test that rich markup in title is preserved.""" + table = create_table( + title="[bold cyan]Test[/bold cyan] [dim]subtitle[/dim]" + ) + + assert "[bold cyan]Test[/bold cyan]" in table.title + assert "[dim]subtitle[/dim]" in table.title From 99b519bef012a551b7dd2a3fb8e48d4cda68cade Mon Sep 17 00:00:00 2001 From: leonace924 Date: Mon, 22 Dec 2025 20:35:41 -0500 Subject: [PATCH 3/6] ruff --- tests/unit_tests/test_utils.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/unit_tests/test_utils.py b/tests/unit_tests/test_utils.py index 22e4135d..5d60ac65 100644 --- a/tests/unit_tests/test_utils.py +++ b/tests/unit_tests/test_utils.py @@ -242,9 +242,15 @@ def test_registration_pattern(self): ), ) - table.add_column("Netuid", style="rgb(253,246,227)", no_wrap=True, justify="center") - table.add_column("Symbol", style=COLOR_PALETTE["GENERAL"]["SYMBOL"], no_wrap=True) - table.add_column("Cost (τ)", style=COLOR_PALETTE["POOLS"]["TAO"], justify="center") + table.add_column( + "Netuid", style="rgb(253,246,227)", no_wrap=True, justify="center" + ) + table.add_column( + "Symbol", style=COLOR_PALETTE["GENERAL"]["SYMBOL"], no_wrap=True + ) + table.add_column( + "Cost (τ)", style=COLOR_PALETTE["POOLS"]["TAO"], justify="center" + ) assert len(table.columns) == 3 @@ -296,9 +302,7 @@ def test_multiple_column_objects_with_styling(self): def test_rich_markup_in_title(self): """Test that rich markup in title is preserved.""" - table = create_table( - title="[bold cyan]Test[/bold cyan] [dim]subtitle[/dim]" - ) + table = create_table(title="[bold cyan]Test[/bold cyan] [dim]subtitle[/dim]") assert "[bold cyan]Test[/bold cyan]" in table.title assert "[dim]subtitle[/dim]" in table.title From 6046aa55c4002b0f21303e0e6cd36c11c6ae1053 Mon Sep 17 00:00:00 2001 From: leonace924 Date: Mon, 22 Dec 2025 20:50:24 -0500 Subject: [PATCH 4/6] feat: refactor move.py and remove.py with create_table --- bittensor_cli/src/commands/stake/move.py | 21 ++--------- bittensor_cli/src/commands/stake/remove.py | 41 +++------------------- 2 files changed, 8 insertions(+), 54 deletions(-) diff --git a/bittensor_cli/src/commands/stake/move.py b/bittensor_cli/src/commands/stake/move.py index f28d689f..52b23226 100644 --- a/bittensor_cli/src/commands/stake/move.py +++ b/bittensor_cli/src/commands/stake/move.py @@ -16,6 +16,7 @@ from bittensor_cli.src.bittensor.utils import ( confirm_action, console, + create_table, print_error, group_subnets, get_subnet_name, @@ -167,7 +168,7 @@ async def display_stake_movement_cross_subnets( ) # Create and display table - table = Table( + table = create_table( title=( f"\n[{COLOR_PALETTE.G.HEADER}]" f"Moving stake from: " @@ -178,14 +179,6 @@ async def display_stake_movement_cross_subnets( f"[/{COLOR_PALETTE.G.SUBHEAD}]\nNetwork: {subtensor.network}\n" f"[/{COLOR_PALETTE.G.HEADER}]" ), - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) table.add_column( @@ -352,16 +345,8 @@ async def stake_move_transfer_selection( raise ValueError # Display hotkeys with stakes - table = Table( + table = create_table( title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Hotkeys with Stakes\n", - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) table.add_column("Index", justify="right") table.add_column("Identity", style=COLOR_PALETTE["GENERAL"]["SUBHEADING"]) diff --git a/bittensor_cli/src/commands/stake/remove.py b/bittensor_cli/src/commands/stake/remove.py index eb930a60..d1490e9f 100644 --- a/bittensor_cli/src/commands/stake/remove.py +++ b/bittensor_cli/src/commands/stake/remove.py @@ -18,6 +18,7 @@ from bittensor_cli.src.bittensor.utils import ( confirm_action, console, + create_table, print_success, print_verbose, print_error, @@ -450,21 +451,13 @@ async def unstake_all( if not unstake_all_alpha else "Unstaking Summary - All Alpha Stakes" ) - table = Table( + table = create_table( title=( f"\n[{COLOR_PALETTE.G.HEADER}]{table_title}[/{COLOR_PALETTE.G.HEADER}]\n" f"Wallet: [{COLOR_PALETTE.G.COLDKEY}]{wallet.name}[/{COLOR_PALETTE.G.COLDKEY}], " f"Coldkey ss58: [{COLOR_PALETTE.G.CK}]{coldkey_ss58}[/{COLOR_PALETTE.G.CK}]\n" f"Network: [{COLOR_PALETTE.G.HEADER}]{subtensor.network}[/{COLOR_PALETTE.G.HEADER}]\n" ), - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) table.add_column("Netuid", justify="center", style="grey89") table.add_column( @@ -1055,16 +1048,8 @@ async def _unstake_selection( # Display existing hotkeys, id, and staked netuids. subnet_filter = f" for Subnet {netuid}" if netuid is not None else "" - table = Table( + table = create_table( title=f"\n[{COLOR_PALETTE.G.HEADER}]Hotkeys with Stakes{subnet_filter}\n", - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) table.add_column("Index", justify="right") table.add_column("Identity", style=COLOR_PALETTE.G.SUBHEAD) @@ -1092,18 +1077,10 @@ async def _unstake_selection( netuid_stakes = hotkey_stakes[selected_hotkey_ss58] # Display hotkey's staked netuids with amount. - table = Table( + table = create_table( title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Stakes for hotkey \n" f"[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{selected_hotkey_name}\n" f"{selected_hotkey_ss58}\n", - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) table.add_column("Subnet", justify="right") table.add_column("Symbol", style=COLOR_PALETTE["GENERAL"]["SYMBOL"]) @@ -1341,16 +1318,8 @@ def _create_unstake_table( f"Coldkey ss58: [{COLOR_PALETTE.G.CK}]{wallet_coldkey_ss58}[/{COLOR_PALETTE.G.CK}]\n" f"Network: {network}[/{COLOR_PALETTE.G.HEADER}]\n" ) - table = Table( + table = create_table( title=title, - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) table.add_column("Netuid", justify="center", style="grey89") From ae7378d1eb70903e9e651b07e130013bc162044c Mon Sep 17 00:00:00 2001 From: leonace924 Date: Mon, 22 Dec 2025 21:11:38 -0500 Subject: [PATCH 5/6] feat: refactor Table to create_table --- bittensor_cli/src/commands/stake/add.py | 11 ++-------- .../src/commands/stake/auto_staking.py | 20 +++---------------- bittensor_cli/src/commands/stake/move.py | 19 ++++++++---------- bittensor_cli/src/commands/stake/wizard.py | 11 +++++----- 4 files changed, 18 insertions(+), 43 deletions(-) diff --git a/bittensor_cli/src/commands/stake/add.py b/bittensor_cli/src/commands/stake/add.py index 275049be..b9bff970 100644 --- a/bittensor_cli/src/commands/stake/add.py +++ b/bittensor_cli/src/commands/stake/add.py @@ -17,6 +17,7 @@ from bittensor_cli.src.bittensor.utils import ( confirm_action, console, + create_table, get_hotkey_wallets_for_wallet, is_valid_ss58_address, print_error, @@ -651,19 +652,11 @@ def _define_stake_table( Returns: Table: An initialized rich Table object with appropriate columns """ - table = Table( + table = create_table( title=f"\n[{COLOR_PALETTE.G.HEADER}]Staking to:\n" f"Wallet: [{COLOR_PALETTE.G.CK}]{wallet.name}[/{COLOR_PALETTE.G.CK}], " f"Coldkey ss58: [{COLOR_PALETTE.G.CK}]{wallet.coldkeypub.ss58_address}[/{COLOR_PALETTE.G.CK}]\n" f"Network: {subtensor.network}[/{COLOR_PALETTE.G.HEADER}]\n", - show_footer=True, - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, ) table.add_column("Netuid", justify="center", style="grey89") diff --git a/bittensor_cli/src/commands/stake/auto_staking.py b/bittensor_cli/src/commands/stake/auto_staking.py index 3d788832..0afee7bc 100644 --- a/bittensor_cli/src/commands/stake/auto_staking.py +++ b/bittensor_cli/src/commands/stake/auto_staking.py @@ -4,12 +4,12 @@ from bittensor_wallet import Wallet from rich import box -from rich.table import Table from bittensor_cli.src import COLOR_PALETTE from bittensor_cli.src.bittensor.utils import ( confirm_action, console, + create_table, json_console, print_success, get_subnet_name, @@ -127,7 +127,7 @@ def resolve_identity(hotkey: str) -> Optional[str]: json_console.print(json.dumps(data_output)) return data_output - table = Table( + table = create_table( title=( f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Auto Stake Destinations" f" for [bold]{coldkey_display}[/bold]\n" @@ -135,13 +135,6 @@ def resolve_identity(hotkey: str) -> Optional[str]: f"Coldkey: {coldkey_ss58}\n" f"[/{COLOR_PALETTE['GENERAL']['HEADER']}]" ), - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, box=box.SIMPLE_HEAD, ) @@ -214,18 +207,11 @@ async def set_auto_stake_destination( hotkey_identity = delegate_info.display if prompt_user and not json_output: - table = Table( + table = create_table( title=( f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Confirm Auto-Stake Destination" f"[/{COLOR_PALETTE['GENERAL']['HEADER']}]" ), - show_edge=False, - header_style="bold white", - border_style="bright_black", - style="bold", - title_justify="center", - show_lines=False, - pad_edge=True, box=box.SIMPLE_HEAD, ) table.add_column( diff --git a/bittensor_cli/src/commands/stake/move.py b/bittensor_cli/src/commands/stake/move.py index 52b23226..69934f53 100644 --- a/bittensor_cli/src/commands/stake/move.py +++ b/bittensor_cli/src/commands/stake/move.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Optional from bittensor_wallet import Wallet -from rich.table import Table from rich.prompt import Prompt from bittensor_cli.src import COLOR_PALETTE @@ -390,13 +389,12 @@ async def stake_move_transfer_selection( origin_hotkey_ss58 = origin_hotkey_info["hotkey_ss58"] # Display available netuids for selected hotkey - table = Table( + table = create_table( title=f"\n[{COLOR_PALETTE.G.HEADER}]Available Stakes for Hotkey\n[/{COLOR_PALETTE.G.HEADER}]" f"[{COLOR_PALETTE.G.HK}]{origin_hotkey_ss58}[/{COLOR_PALETTE.G.HK}]\n", - show_edge=False, - header_style="bold white", - border_style="bright_black", - title_justify="center", + show_footer=False, + show_lines=True, + pad_edge=False, width=len(origin_hotkey_ss58) + 20, ) table.add_column("Netuid", style="cyan") @@ -468,13 +466,12 @@ async def stake_swap_selection( raise ValueError # Display available stakes - table = Table( + table = create_table( title=f"\n[{COLOR_PALETTE.G.HEADER}]Available Stakes for Hotkey\n[/{COLOR_PALETTE.G.HEADER}]" f"[{COLOR_PALETTE.G.HK}]{wallet.hotkey_str}: {hotkey_ss58}[/{COLOR_PALETTE.G.HK}]\n", - show_edge=False, - header_style="bold white", - border_style="bright_black", - title_justify="center", + show_footer=False, + show_lines=True, + pad_edge=False, width=len(hotkey_ss58) + 20, ) diff --git a/bittensor_cli/src/commands/stake/wizard.py b/bittensor_cli/src/commands/stake/wizard.py index f1886f65..1b11f93c 100644 --- a/bittensor_cli/src/commands/stake/wizard.py +++ b/bittensor_cli/src/commands/stake/wizard.py @@ -10,12 +10,12 @@ from bittensor_wallet import Wallet from rich.prompt import Prompt -from rich.table import Table from rich.panel import Panel from bittensor_cli.src import COLOR_PALETTE from bittensor_cli.src.bittensor.utils import ( console, + create_table, print_error, is_valid_ss58_address, get_hotkey_pub_ss58, @@ -159,12 +159,11 @@ def get_identity(hotkey_ss58_: str) -> str: return old_identity.display return "~" - table = Table( + table = create_table( title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Your Available Stakes[/{COLOR_PALETTE['GENERAL']['HEADER']}]\n", - show_edge=False, - header_style="bold white", - border_style="bright_black", - title_justify="center", + show_footer=False, + show_lines=True, + pad_edge=False, ) table.add_column("Hotkey Identity", style=COLOR_PALETTE["GENERAL"]["SUBHEADING"]) From d43f8d85686252d1a4dd9aef9bb94e7e1f258333 Mon Sep 17 00:00:00 2001 From: leonace924 Date: Tue, 23 Dec 2025 19:11:07 -0500 Subject: [PATCH 6/6] fix: revert the test of table --- tests/unit_tests/test_utils.py | 175 --------------------------------- 1 file changed, 175 deletions(-) diff --git a/tests/unit_tests/test_utils.py b/tests/unit_tests/test_utils.py index 5d60ac65..6a3774d0 100644 --- a/tests/unit_tests/test_utils.py +++ b/tests/unit_tests/test_utils.py @@ -5,10 +5,7 @@ from bittensor_cli.src.bittensor.utils import ( check_img_mimetype, confirm_action, - create_table, ) -from rich.table import Column, Table -from bittensor_cli.src import COLOR_PALETTE @pytest.mark.parametrize( @@ -134,175 +131,3 @@ def test_confirm_action_default_values(self): result = confirm_action("Do you want to proceed?") assert result is True mock_ask.assert_called_once() - - -class TestCreateTable: - """Tests for the create_table utility function.""" - - def test_simple_table_creation(self): - """Test creating a simple table with default styling.""" - table = create_table(title="My Subnets") - - # Verify it returns a Table instance - assert isinstance(table, Table) - assert table.title == "My Subnets" - - # Verify default styling is applied - assert table.show_footer is True - assert table.show_edge is False - assert table.header_style == "bold white" - assert table.border_style == "bright_black" - assert table.title_justify == "center" - assert table.show_lines is False - assert table.pad_edge is True - - def test_table_with_columns_added_later(self): - """Test adding columns after table creation.""" - table = create_table(title="Test Table") - - # Add columns dynamically - table.add_column("Column1", justify="center") - table.add_column("Column2", justify="left") - - assert len(table.columns) == 2 - assert table.columns[0].header == "Column1" - assert table.columns[1].header == "Column2" - - # Add rows - table.add_row("Value1", "Value2") - assert len(table.rows) == 1 - - def test_table_with_column_objects(self): - """Test creating table with Column objects upfront (identity table pattern).""" - table = create_table( - Column( - "Item", - justify="right", - style=COLOR_PALETTE["GENERAL"]["SUBHEADING_MAIN"], - no_wrap=True, - ), - Column("Value", style=COLOR_PALETTE["GENERAL"]["SUBHEADING"]), - title="Identity", - ) - - # Verify columns were added - assert len(table.columns) == 2 - assert table.columns[0].header == "Item" - assert table.columns[1].header == "Value" - assert table.columns[0].justify == "right" - assert table.columns[0].no_wrap is True - - # Verify default styling still applied - assert table.show_footer is True - assert table.show_edge is False - - def test_custom_overrides(self): - """Test overriding default parameters.""" - table = create_table( - title="Custom Table", - show_footer=False, - border_style="blue", - show_lines=True, - ) - - # Verify overrides applied - assert table.show_footer is False - assert table.border_style == "blue" - assert table.show_lines is True - - # Verify non-overridden defaults preserved - assert table.show_edge is False - assert table.header_style == "bold white" - - def test_subnets_list_pattern(self): - """Test actual pattern from subnets_list() function.""" - table = create_table( - title=f"[{COLOR_PALETTE['GENERAL']['HEADER']}]Subnets\n" - f"Network: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]finney\n", - ) - - # Add columns as in actual code - table.add_column("[bold white]Netuid", style="grey89", justify="center") - table.add_column("[bold white]Name", style="cyan", justify="left") - table.add_column("[bold white]Price", style="dark_sea_green2", justify="left") - - assert len(table.columns) == 3 - - # Add sample row - table.add_row("1", "Alpha", "0.0025") - assert len(table.rows) == 1 - - def test_registration_pattern(self): - """Test registration confirmation table pattern.""" - table = create_table( - title=( - f"[{COLOR_PALETTE.G.HEADER}]" - f"Register to [{COLOR_PALETTE.G.SUBHEAD}]netuid: 1[/{COLOR_PALETTE.G.SUBHEAD}]\n" - f"Network: [{COLOR_PALETTE.G.SUBHEAD}]finney[/{COLOR_PALETTE.G.SUBHEAD}]\n" - ), - ) - - table.add_column( - "Netuid", style="rgb(253,246,227)", no_wrap=True, justify="center" - ) - table.add_column( - "Symbol", style=COLOR_PALETTE["GENERAL"]["SYMBOL"], no_wrap=True - ) - table.add_column( - "Cost (τ)", style=COLOR_PALETTE["POOLS"]["TAO"], justify="center" - ) - - assert len(table.columns) == 3 - - # Add sample row - table.add_row("1", "α", "τ 0.5000") - assert len(table.rows) == 1 - - def test_advanced_rich_features(self): - """Test advanced Rich features with custom box and expand.""" - from rich import box - - table = create_table( - Column("Command", overflow="fold", ratio=2), - Column("Description", overflow="fold", ratio=3), - title="Commands", - box=box.ROUNDED, - expand=True, - padding=(0, 1), - ) - - assert table.box == box.ROUNDED - assert table.expand is True - assert len(table.columns) == 2 - assert table.columns[0].ratio == 2 - assert table.columns[1].ratio == 3 - - def test_empty_table_minimal_config(self): - """Test creating empty table with minimal configuration.""" - table = create_table() - - assert isinstance(table, Table) - assert table.title == "" - assert table.show_footer is True - assert len(table.columns) == 0 - - def test_multiple_column_objects_with_styling(self): - """Test multiple Column objects with various styling options.""" - table = create_table( - Column("Col1", style="cyan", justify="left"), - Column("Col2", style="green", justify="center", no_wrap=True), - Column("Col3", style="yellow", justify="right", overflow="fold"), - title="Multi-Column Test", - ) - - assert len(table.columns) == 3 - assert table.columns[0].style == "cyan" - assert table.columns[1].justify == "center" - assert table.columns[2].overflow == "fold" - - def test_rich_markup_in_title(self): - """Test that rich markup in title is preserved.""" - table = create_table(title="[bold cyan]Test[/bold cyan] [dim]subtitle[/dim]") - - assert "[bold cyan]Test[/bold cyan]" in table.title - assert "[dim]subtitle[/dim]" in table.title