diff --git a/CHANGELOG.md b/CHANGELOG.md index 864526241..7de27c26b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 9.8.6 /2025-07-22 +* Hyperparam discrepancy between set/get by @thewhaleking in https://github.com/opentensor/btcli/pull/552 +* Hyperparameters in alphabetical order for `btcli sudo get/set` by @basfroman in https://github.com/opentensor/btcli/pull/553 + +**Full Changelog**: https://github.com/opentensor/btcli/compare/v9.8.5...v9.8.6 + ## 9.8.5 /2025-07-16 * Updates `user_liquidity_enabled` to not root sudo only. by @thewhaleking in https://github.com/opentensor/btcli/pull/546 * Patches broken Brahmi characters with normal characters. by @thewhaleking in https://github.com/opentensor/btcli/pull/547 diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index fdf7ce2a2..d751e06ad 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -1070,7 +1070,8 @@ def initialize_chain( not_selected_networks = [net for net in network if net != network_] if not_selected_networks: console.print( - f"Networks not selected: [dark_orange]{', '.join(not_selected_networks)}[/dark_orange]" + f"Networks not selected: " + f"[{COLORS.G.ARG}]{', '.join(not_selected_networks)}[/{COLORS.G.ARG}]" ) self.subtensor = SubtensorInterface(network_) @@ -1353,8 +1354,8 @@ def set_config( if n := args.get("network"): if n in Constants.networks: if not Confirm.ask( - f"You provided a network [dark_orange]{n}[/dark_orange] which is mapped to " - f"[dark_orange]{Constants.network_map[n]}[/dark_orange]\n" + f"You provided a network [{COLORS.G.ARG}]{n}[/{COLORS.G.ARG}] which is mapped to " + f"[{COLORS.G.ARG}]{Constants.network_map[n]}[/{COLORS.G.ARG}]\n" "Do you want to continue?" ): typer.Exit() @@ -1369,14 +1370,14 @@ def set_config( ) args["network"] = known_network if not Confirm.ask( - f"You provided an endpoint [dark_orange]{n}[/dark_orange] which is mapped to " - f"[dark_orange]{known_network}[/dark_orange]\n" + f"You provided an endpoint [{COLORS.G.ARG}]{n}[/{COLORS.G.ARG}] which is mapped to " + f"[{COLORS.G.ARG}]{known_network}[/{COLORS.G.ARG}]\n" "Do you want to continue?" ): - typer.Exit() + raise typer.Exit() else: if not Confirm.ask( - f"You provided a chain endpoint URL [dark_orange]{n}[/dark_orange]\n" + f"You provided a chain endpoint URL [{COLORS.G.ARG}]{n}[/{COLORS.G.ARG}]\n" "Do you want to continue?" ): raise typer.Exit() @@ -1451,15 +1452,15 @@ def del_config( for arg in args.keys(): if self.config.get(arg) is not None: if Confirm.ask( - f"Do you want to clear the [dark_orange]{arg}[/dark_orange] config?" + f"Do you want to clear the [{COLORS.G.ARG}]{arg}[/{COLORS.G.ARG}] config?" ): self.config[arg] = None console.print( - f"Cleared [dark_orange]{arg}[/dark_orange] config and set to 'None'." + f"Cleared [{COLORS.G.ARG}]{arg}[/{COLORS.G.ARG}] config and set to 'None'." ) else: console.print( - f"Skipped clearing [dark_orange]{arg}[/dark_orange] config." + f"Skipped clearing [{COLORS.G.ARG}]{arg}[/{COLORS.G.ARG}] config." ) else: @@ -1468,19 +1469,21 @@ def del_config( if should_clear: if self.config.get(arg) is not None: if Confirm.ask( - f"Do you want to clear the [dark_orange]{arg}[/dark_orange] [bold cyan]({self.config.get(arg)})[/bold cyan] config?" + f"Do you want to clear the [{COLORS.G.ARG}]{arg}[/{COLORS.G.ARG}]" + f" [bold cyan]({self.config.get(arg)})[/bold cyan] config?" ): self.config[arg] = None console.print( - f"Cleared [dark_orange]{arg}[/dark_orange] config and set to 'None'." + f"Cleared [{COLORS.G.ARG}]{arg}[/{COLORS.G.ARG}] config and set to 'None'." ) else: console.print( - f"Skipped clearing [dark_orange]{arg}[/dark_orange] config." + f"Skipped clearing [{COLORS.G.ARG}]{arg}[/{COLORS.G.ARG}] config." ) else: console.print( - f"No config set for [dark_orange]{arg}[/dark_orange]. Use `btcli config set` to set it." + f"No config set for [{COLORS.G.ARG}]{arg}[/{COLORS.G.ARG}]." + f" Use [{COLORS.G.ARG}]`btcli config set`[/{COLORS.G.ARG}] to set it." ) with open(self.config_path, "w") as f: safe_dump(self.config, f) @@ -1492,7 +1495,7 @@ def get_config(self): deprecated_configs = ["chain"] table = Table( - Column("[bold white]Name", style="dark_orange"), + Column("[bold white]Name", style=f"{COLORS.G.ARG}"), Column("[bold white]Value", style="gold1"), Column("", style="medium_purple"), box=box.SIMPLE_HEAD, @@ -4594,7 +4597,9 @@ def sudo_set( "Param name not supplied with `--no-prompt` flag. Cannot continue" ) return False - hyperparam_list = [field.name for field in fields(SubnetHyperparameters)] + hyperparam_list = sorted( + [field.name for field in fields(SubnetHyperparameters)] + ) console.print("Available hyperparameters:\n") for idx, param in enumerate(hyperparam_list, start=1): console.print(f" {idx}. {param}") @@ -4609,17 +4614,44 @@ def sudo_set( if param_name in ["alpha_high", "alpha_low"]: if not prompt: err_console.print( - "`alpha_high` and `alpha_low` values cannot be set with `--no-prompt`" + f"[{COLORS.SU.HYPERPARAM}]alpha_high[/{COLORS.SU.HYPERPARAM}] and " + f"[{COLORS.SU.HYPERPARAM}]alpha_low[/{COLORS.SU.HYPERPARAM}] " + f"values cannot be set with `--no-prompt`" ) return False param_name = "alpha_values" low_val = FloatPrompt.ask( - "Enter the new value for [dark_orange]alpha_low[/dark_orange]" + f"Enter the new value for [{COLORS.G.ARG}]alpha_low[/{COLORS.G.ARG}]" ) high_val = FloatPrompt.ask( - "Enter the new value for [dark_orange]alpha_high[/dark_orange]" + f"Enter the new value for [{COLORS.G.ARG}]alpha_high[/{COLORS.G.ARG}]" ) param_value = f"{low_val},{high_val}" + if param_name == "yuma_version": + if not prompt: + err_console.print( + f"[{COLORS.SU.HYPERPARAM}]yuma_version[/{COLORS.SU.HYPERPARAM}]" + f" is set using a different hyperparameter, and thus cannot be set with `--no-prompt`" + ) + return False + if Confirm.ask( + f"[{COLORS.SU.HYPERPARAM}]yuma_version[/{COLORS.SU.HYPERPARAM}] can only be used to toggle Yuma 3. " + f"Would you like to toggle Yuma 3?" + ): + param_name = "yuma3_enabled" + question = Prompt.ask( + "Would to like to enable or disable Yuma 3?", + choices=["enable", "disable"], + ) + param_value = "true" if question == "enable" else "false" + else: + return False + if param_name == "subnet_is_active": + err_console.print( + f"[{COLORS.SU.HYPERPARAM}]subnet_is_active[/{COLORS.SU.HYPERPARAM}] " + f"is set by using [{COLORS.G.ARG}]`btcli subnets start`[/{COLORS.G.ARG}] command." + ) + return False if not param_value: if not prompt: diff --git a/bittensor_cli/src/__init__.py b/bittensor_cli/src/__init__.py index 6c178a818..ebb01b433 100644 --- a/bittensor_cli/src/__init__.py +++ b/bittensor_cli/src/__init__.py @@ -661,6 +661,8 @@ class WalletValidationTypes(Enum): "yuma3_enabled": ("sudo_set_yuma3_enabled", False), "alpha_sigmoid_steepness": ("sudo_set_alpha_sigmoid_steepness", True), "user_liquidity_enabled": ("toggle_user_liquidity", False), + "bonds_reset_enabled": ("sudo_set_bonds_reset_enabled", False), + "transfers_enabled": ("sudo_set_toggle_transfer", False), } HYPERPARAMS_MODULE = { @@ -747,6 +749,7 @@ class General(Gettable): NETUID = "#CBA880" # Tan NETUID_EXTRA = "#DDD5A9" # Light Khaki TEMPO = "#67A3A5" # Grayish Teal + ARG = "dark_orange" # aliases CK = COLDKEY HK = HOTKEY diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index 88032df89..8004dc90f 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -671,7 +671,8 @@ async def get_hyperparameters( dict_out = [] normalized_values = normalize_hyperparameters(subnet, json_output=json_output) - for param, value, norm_value in normalized_values: + sorted_values = sorted(normalized_values, key=lambda x: x[0]) + for param, value, norm_value in sorted_values: if not json_output: table.add_row(" " + param, value, norm_value) else: diff --git a/pyproject.toml b/pyproject.toml index 432b85b81..e310a0f35 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "bittensor-cli" -version = "9.8.5" +version = "9.8.6" description = "Bittensor CLI" readme = "README.md" authors = [ diff --git a/tests/e2e_tests/test_staking_sudo.py b/tests/e2e_tests/test_staking_sudo.py index 3225b9e6e..8cb5caca4 100644 --- a/tests/e2e_tests/test_staking_sudo.py +++ b/tests/e2e_tests/test_staking_sudo.py @@ -396,20 +396,17 @@ def test_staking(local_chain, wallet_setup): hyperparams = exec_command_alice( command="sudo", sub_command="get", - extra_args=[ - "--chain", - "ws://127.0.0.1:9945", - "--netuid", - netuid, - ], + extra_args=["--chain", "ws://127.0.0.1:9945", "--netuid", netuid, "--json-out"], ) # Parse all hyperparameters and single out max_burn in TAO - all_hyperparams = hyperparams.stdout.splitlines() - max_burn_tao = all_hyperparams[22].split()[2].strip("\u200e") + all_hyperparams = json.loads(hyperparams.stdout) + max_burn_tao = next( + filter(lambda x: x["hyperparameter"] == "max_burn", all_hyperparams) + )["value"] # Assert max_burn is 100 TAO from default - assert Balance.from_tao(float(max_burn_tao)) == Balance.from_tao(100.0) + assert Balance.from_rao(int(max_burn_tao)) == Balance.from_tao(100.0) hyperparams_json = exec_command_alice( command="sudo", @@ -468,7 +465,11 @@ def test_staking(local_chain, wallet_setup): # Parse updated hyperparameters all_updated_hyperparams = updated_hyperparams.stdout.splitlines() - updated_max_burn_tao = all_updated_hyperparams[22].split()[2].strip("\u200e") + updated_max_burn_tao = ( + next(filter(lambda x: x[3:11] == "max_burn", all_updated_hyperparams)) + .split()[2] + .strip("\u200e") + ) # Assert max_burn is now 10 TAO assert Balance.from_tao(float(updated_max_burn_tao)) == Balance.from_tao(10)