Skip to content
Merged
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
70 changes: 51 additions & 19 deletions bittensor_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_)
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand Down Expand Up @@ -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:
Expand All @@ -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)
Expand All @@ -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,
Expand Down Expand Up @@ -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}")
Expand All @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions bittensor_cli/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion bittensor_cli/src/commands/sudo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
21 changes: 11 additions & 10 deletions tests/e2e_tests/test_staking_sudo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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)
Expand Down
Loading