bittensor-cli 9.3.0__py3-none-any.whl → 9.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -238,25 +238,25 @@ class SubtensorInterface:
238
238
 
239
239
  :return: Balance: The stake under the coldkey - hotkey pairing.
240
240
  """
241
- alpha_shares = await self.query(
242
- module="SubtensorModule",
243
- storage_function="Alpha",
244
- params=[hotkey_ss58, coldkey_ss58, netuid],
245
- block_hash=block_hash,
246
- )
247
-
248
- hotkey_alpha = await self.query(
249
- module="SubtensorModule",
250
- storage_function="TotalHotkeyAlpha",
251
- params=[hotkey_ss58, netuid],
252
- block_hash=block_hash,
253
- )
254
-
255
- hotkey_shares = await self.query(
256
- module="SubtensorModule",
257
- storage_function="TotalHotkeyShares",
258
- params=[hotkey_ss58, netuid],
259
- block_hash=block_hash,
241
+ alpha_shares, hotkey_alpha, hotkey_shares = await asyncio.gather(
242
+ self.query(
243
+ module="SubtensorModule",
244
+ storage_function="Alpha",
245
+ params=[hotkey_ss58, coldkey_ss58, netuid],
246
+ block_hash=block_hash,
247
+ ),
248
+ self.query(
249
+ module="SubtensorModule",
250
+ storage_function="TotalHotkeyAlpha",
251
+ params=[hotkey_ss58, netuid],
252
+ block_hash=block_hash,
253
+ ),
254
+ self.query(
255
+ module="SubtensorModule",
256
+ storage_function="TotalHotkeyShares",
257
+ params=[hotkey_ss58, netuid],
258
+ block_hash=block_hash,
259
+ ),
260
260
  )
261
261
 
262
262
  alpha_shares_as_float = fixed_to_float(alpha_shares or 0)
@@ -31,6 +31,7 @@ from bittensor_cli.src import defaults, Constants
31
31
 
32
32
  if TYPE_CHECKING:
33
33
  from bittensor_cli.src.bittensor.chain_data import SubnetHyperparameters
34
+ from rich.prompt import PromptBase
34
35
 
35
36
  console = Console()
36
37
  json_console = Console()
@@ -557,7 +558,10 @@ def format_error_message(error_message: Union[dict, Exception]) -> str:
557
558
  err_type = error_message.get("type", err_type)
558
559
  err_name = error_message.get("name", err_name)
559
560
  err_docs = error_message.get("docs", [err_description])
560
- err_description = err_docs[0] if err_docs else err_description
561
+ if isinstance(err_docs, list):
562
+ err_description = " ".join(err_docs)
563
+ else:
564
+ err_description = err_docs
561
565
 
562
566
  return f"Subtensor returned `{err_name}({err_type})` error. This means: `{err_description}`."
563
567
 
@@ -1007,7 +1011,7 @@ def retry_prompt(
1007
1011
  rejection_text: str,
1008
1012
  default="",
1009
1013
  show_default=False,
1010
- prompt_type=Prompt.ask,
1014
+ prompt_type: "PromptBase.ask" = Prompt.ask,
1011
1015
  ):
1012
1016
  """
1013
1017
  Allows for asking prompts again if they do not meet a certain criteria (as defined in `rejection`)
@@ -10,7 +10,7 @@ from rich.progress import Progress, BarColumn, TextColumn
10
10
  from rich.table import Column, Table
11
11
  from rich import box
12
12
 
13
- from bittensor_cli.src import COLOR_PALETTE
13
+ from bittensor_cli.src import COLOR_PALETTE, Constants
14
14
  from bittensor_cli.src.bittensor.balances import Balance
15
15
  from bittensor_cli.src.bittensor.extrinsics.registration import (
16
16
  register_extrinsic,
@@ -34,6 +34,7 @@ from bittensor_cli.src.bittensor.utils import (
34
34
  prompt_for_identity,
35
35
  get_subnet_name,
36
36
  unlock_key,
37
+ blocks_to_duration,
37
38
  json_console,
38
39
  )
39
40
 
@@ -2308,3 +2309,121 @@ async def get_identity(
2308
2309
  else:
2309
2310
  console.print(table)
2310
2311
  return identity
2312
+
2313
+
2314
+ async def get_start_schedule(
2315
+ subtensor: "SubtensorInterface",
2316
+ netuid: int,
2317
+ ) -> None:
2318
+ """Fetch and display existing emission schedule information."""
2319
+
2320
+ if not await subtensor.subnet_exists(netuid):
2321
+ print_error(f"Subnet {netuid} does not exist.")
2322
+ return None
2323
+ block_hash = await subtensor.substrate.get_chain_head()
2324
+ registration_block, min_blocks_to_start, current_block = await asyncio.gather(
2325
+ subtensor.query(
2326
+ module="SubtensorModule",
2327
+ storage_function="NetworkRegisteredAt",
2328
+ params=[netuid],
2329
+ block_hash=block_hash,
2330
+ ),
2331
+ subtensor.substrate.get_constant(
2332
+ module_name="SubtensorModule",
2333
+ constant_name="DurationOfStartCall",
2334
+ block_hash=block_hash,
2335
+ ),
2336
+ subtensor.substrate.get_block_number(block_hash=block_hash),
2337
+ )
2338
+
2339
+ potential_start_block = registration_block + min_blocks_to_start
2340
+ if current_block < potential_start_block:
2341
+ blocks_to_wait = potential_start_block - current_block
2342
+ time_to_wait = blocks_to_duration(blocks_to_wait)
2343
+
2344
+ console.print(
2345
+ f"[blue]Subnet {netuid}[/blue]:\n"
2346
+ f"[blue]Registered at:[/blue] {registration_block}\n"
2347
+ f"[blue]Minimum start block:[/blue] {potential_start_block}\n"
2348
+ f"[blue]Current block:[/blue] {current_block}\n"
2349
+ f"[blue]Blocks remaining:[/blue] {blocks_to_wait}\n"
2350
+ f"[blue]Time to wait:[/blue] {time_to_wait}"
2351
+ )
2352
+ else:
2353
+ console.print(
2354
+ f"[blue]Subnet {netuid}[/blue]:\n"
2355
+ f"[blue]Registered at:[/blue] {registration_block}\n"
2356
+ f"[blue]Current block:[/blue] {current_block}\n"
2357
+ f"[blue]Minimum start block:[/blue] {potential_start_block}\n"
2358
+ f"[dark_sea_green3]Emission schedule can be started[/dark_sea_green3]"
2359
+ )
2360
+
2361
+ return
2362
+
2363
+
2364
+ async def start_subnet(
2365
+ wallet: "Wallet",
2366
+ subtensor: "SubtensorInterface",
2367
+ netuid: int,
2368
+ prompt: bool = False,
2369
+ ) -> bool:
2370
+ """Start a subnet's emission schedule"""
2371
+
2372
+ if not await subtensor.subnet_exists(netuid):
2373
+ print_error(f"Subnet {netuid} does not exist.")
2374
+ return False
2375
+
2376
+ subnet_owner = await subtensor.query(
2377
+ module="SubtensorModule",
2378
+ storage_function="SubnetOwner",
2379
+ params=[netuid],
2380
+ )
2381
+ if subnet_owner != wallet.coldkeypub.ss58_address:
2382
+ print_error(":cross_mark: This wallet doesn't own the specified subnet.")
2383
+ return False
2384
+
2385
+ if prompt:
2386
+ if not Confirm.ask(
2387
+ f"Are you sure you want to start subnet {netuid}'s emission schedule?"
2388
+ ):
2389
+ return False
2390
+
2391
+ if not unlock_key(wallet).success:
2392
+ return False
2393
+
2394
+ with console.status(
2395
+ f":satellite: Starting subnet {netuid}'s emission schedule...", spinner="earth"
2396
+ ):
2397
+ start_call = await subtensor.substrate.compose_call(
2398
+ call_module="SubtensorModule",
2399
+ call_function="start_call",
2400
+ call_params={"netuid": netuid},
2401
+ )
2402
+
2403
+ signed_ext = await subtensor.substrate.create_signed_extrinsic(
2404
+ call=start_call,
2405
+ keypair=wallet.coldkey,
2406
+ )
2407
+
2408
+ response = await subtensor.substrate.submit_extrinsic(
2409
+ extrinsic=signed_ext,
2410
+ wait_for_inclusion=True,
2411
+ wait_for_finalization=True,
2412
+ )
2413
+
2414
+ if await response.is_success:
2415
+ console.print(
2416
+ f":white_heavy_check_mark: [green]Successfully started subnet {netuid}'s emission schedule.[/green]"
2417
+ )
2418
+ return True
2419
+ else:
2420
+ error_msg = format_error_message(await response.error_message)
2421
+ if "FirstEmissionBlockNumberAlreadySet" in error_msg:
2422
+ console.print(
2423
+ f"[dark_sea_green3]Subnet {netuid} already has an emission schedule.[/dark_sea_green3]"
2424
+ )
2425
+ return True
2426
+
2427
+ await get_start_schedule(subtensor, netuid)
2428
+ print_error(f":cross_mark: Failed to start subnet: {error_msg}")
2429
+ return False
@@ -145,6 +145,7 @@ async def set_hyperparameter_extrinsic(
145
145
  value: Optional[Union[str, bool, float, list[float]]],
146
146
  wait_for_inclusion: bool = False,
147
147
  wait_for_finalization: bool = True,
148
+ prompt: bool = True,
148
149
  ) -> bool:
149
150
  """Sets a hyperparameter for a specific subnetwork.
150
151
 
@@ -190,7 +191,7 @@ async def set_hyperparameter_extrinsic(
190
191
  ":cross_mark: [red]Invalid hyperparameter specified.[/red]"
191
192
  )
192
193
  return False
193
- if sudo_:
194
+ if sudo_ and prompt:
194
195
  if not Confirm.ask(
195
196
  "This hyperparam is only settable by root sudo users. If you are not, this will fail. Please confirm"
196
197
  ):
@@ -574,6 +575,7 @@ async def sudo_set_hyperparameter(
574
575
  netuid: int,
575
576
  param_name: str,
576
577
  param_value: Optional[str],
578
+ prompt: bool,
577
579
  json_output: bool,
578
580
  ):
579
581
  """Set subnet hyperparameters."""
@@ -602,7 +604,7 @@ async def sudo_set_hyperparameter(
602
604
  )
603
605
  return False
604
606
  success = await set_hyperparameter_extrinsic(
605
- subtensor, wallet, netuid, param_name, value
607
+ subtensor, wallet, netuid, param_name, value, prompt=prompt
606
608
  )
607
609
  if json_output:
608
610
  return success
bittensor_cli/version.py CHANGED
@@ -3,18 +3,20 @@ import re
3
3
 
4
4
 
5
5
  def version_as_int(version):
6
- _core_version = re.match(r"^\d+\.\d+\.\d+", version).group(0)
7
- _version_split = _core_version.split(".")
8
- __version_info__ = tuple(int(part) for part in _version_split)
9
- _version_int_base = 1000
10
- assert max(__version_info__) < _version_int_base
6
+ match = re.match(r"^\d+\.\d+\.\d+", version)
7
+ if not match:
8
+ raise ValueError(f"Invalid version format: {version}")
9
+ core_version = match.group(0)
10
+ version_split = core_version.split(".")
11
+ version_info = tuple(int(part) for part in version_split)
12
+ version_int_base = 1000
13
+ assert max(version_info) < version_int_base
11
14
 
12
- __version_as_int__: int = sum(
13
- e * (_version_int_base**i) for i, e in enumerate(reversed(__version_info__))
15
+ version_as_int_: int = sum(
16
+ e * (version_int_base**i) for i, e in enumerate(reversed(version_info))
14
17
  )
15
- assert __version_as_int__ < 2**31 # fits in int32
16
- __new_signature_version__ = 360
17
- return __version_as_int__
18
+ assert version_as_int_ < 2**31 # fits in int32
19
+ return version_as_int_
18
20
 
19
21
 
20
22
  __version__ = importlib.metadata.version("bittensor-cli")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bittensor-cli
3
- Version: 9.3.0
3
+ Version: 9.4.1
4
4
  Summary: Bittensor CLI
5
5
  Author: bittensor.com
6
6
  Project-URL: homepage, https://github.com/opentensor/btcli
@@ -12,6 +12,7 @@ Requires-Dist: async-property==0.2.2
12
12
  Requires-Dist: async-substrate-interface>=1.1.0
13
13
  Requires-Dist: aiohttp~=3.10.2
14
14
  Requires-Dist: backoff~=2.2.1
15
+ Requires-Dist: click<8.2.0
15
16
  Requires-Dist: GitPython>=3.0.0
16
17
  Requires-Dist: fuzzywuzzy~=0.18.0
17
18
  Requires-Dist: netaddr~=1.3.0
@@ -29,7 +30,7 @@ Requires-Dist: plotille>=5.0.0
29
30
  Requires-Dist: pywry>=0.6.2
30
31
  Requires-Dist: plotly>=6.0.0
31
32
  Provides-Extra: cuda
32
- Requires-Dist: torch<2.6.0,>=1.13.1; extra == "cuda"
33
+ Requires-Dist: torch<3.0,>=1.13.1; extra == "cuda"
33
34
 
34
35
  <div align="center">
35
36
 
@@ -72,7 +73,7 @@ Installation steps are described below. For a full documentation on how to use `
72
73
 
73
74
  ## Install on macOS and Linux
74
75
 
75
- You can install `btcli` on your local machine directly from source, or from from PyPI. **Make sure you verify your installation after you install**:
76
+ You can install `btcli` on your local machine directly from source, or from PyPI. **Make sure you verify your installation after you install**:
76
77
 
77
78
 
78
79
  ### Install from PyPI
@@ -1,21 +1,21 @@
1
1
  bittensor_cli/__init__.py,sha256=Lpv4NkbAQgwrfqFOnTMuR_S-fqGdaWCSLhxnFnGTHM0,1232
2
- bittensor_cli/cli.py,sha256=Of6WY-3dg4SAg_NcDs1Rn3ZYwZre21dQ1-YsD8pkBwU,213143
2
+ bittensor_cli/cli.py,sha256=3tanMizgAIw0b8n-vgqw5GOZwcpEBDHhfarKOzMt4aM,217087
3
3
  bittensor_cli/doc_generation_helper.py,sha256=GexqjEIKulWg84hpNBEchJ840oOgOi7DWpt447nsdNI,91
4
- bittensor_cli/version.py,sha256=xtm9qNHg2cYyMpx8mg2YxuglkVUvseiqJg82z4gTrEY,685
5
- bittensor_cli/src/__init__.py,sha256=jaQx65z8fjvsMSSTjSZkHUUYbv8u65AkzNTy6piVtyc,35418
4
+ bittensor_cli/version.py,sha256=dU1xsa3mG5FPdhzvqlzDByNcCHmzcFQH3q1pQr4u76g,720
5
+ bittensor_cli/src/__init__.py,sha256=dRBcdUWIqHTyusuvuhP4PrRc9MWmnmj76WDWLHxhjmA,33795
6
6
  bittensor_cli/src/bittensor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  bittensor_cli/src/bittensor/balances.py,sha256=q5KkxF8wmUguWAFddEKstfDKTxPe5ISHpT6br8x32rc,11148
8
8
  bittensor_cli/src/bittensor/chain_data.py,sha256=yOQyPZ472BlfhAfaemdi22qunEGHlVvugRdUeYpZxwQ,41663
9
9
  bittensor_cli/src/bittensor/minigraph.py,sha256=BIzmSVLfBYiRAeGD_i1LAC8Cw7zxp38a91SIFEPMqYc,10479
10
10
  bittensor_cli/src/bittensor/networking.py,sha256=pZLMs8YXpZzDMLXWMBb_Bj6TVkm_q9khyY-lnbwVMuE,462
11
- bittensor_cli/src/bittensor/subtensor_interface.py,sha256=JqbraGNGfEfUFff5ZwQJSzIep2IDfuuyFJzzxCr2NLA,58883
12
- bittensor_cli/src/bittensor/utils.py,sha256=CT_uQlJFGqSXMRzsvXu6prt7aDLYEkQFDW-94skSZcM,47588
11
+ bittensor_cli/src/bittensor/subtensor_interface.py,sha256=StNlKxk348cq-nEU-5qye0yMTG5snLU_whw1dALRX2I,58976
12
+ bittensor_cli/src/bittensor/utils.py,sha256=vetZCwy-LSJjYj58f_5wIuTi2A2sHyCMjrHR1DqT6bY,47729
13
13
  bittensor_cli/src/bittensor/extrinsics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  bittensor_cli/src/bittensor/extrinsics/registration.py,sha256=mZt6z8PRK5MaIczLygmVvAUnfl_dl5zDF7ysIFkwHvs,64511
15
15
  bittensor_cli/src/bittensor/extrinsics/root.py,sha256=rVogWhT28NJ1CrVXtbq_Pyi7etB_zTZicbjiHAHLdSs,19214
16
16
  bittensor_cli/src/bittensor/extrinsics/transfer.py,sha256=vxLzKQkTSsV-ark7WAJjEN4QasEJI_9MXt2Dg8eR2j4,8569
17
17
  bittensor_cli/src/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- bittensor_cli/src/commands/sudo.py,sha256=y5PTJEa7LI6vUXazRjXsphMA4lQdKR8axcLZXQSdyp4,32993
18
+ bittensor_cli/src/commands/sudo.py,sha256=or_wkOMf4RAE64pp2SiX2ybeN0V89hlsEf86cyLPsV4,33062
19
19
  bittensor_cli/src/commands/view.py,sha256=2MdhWWbY9rwGqDilzs8r2ioa0l2GzrYxe8pKkavEVWs,109517
20
20
  bittensor_cli/src/commands/wallets.py,sha256=N3ERh4Iw0juJSy9-AUQaTC1SfZsklD-lxCcFfODfcGE,73142
21
21
  bittensor_cli/src/commands/weights.py,sha256=BCJm_mlw0pVK4YEZuEMqQBpvvOoB7B1rzdvMeN3uTfM,16503
@@ -27,9 +27,9 @@ bittensor_cli/src/commands/stake/move.py,sha256=AVeo0l4bvGAtjbdzx2Fn7_-jiI28B7LM
27
27
  bittensor_cli/src/commands/stake/remove.py,sha256=l7TtLK2Z6-TJ5-DEwUzm6HT2GQC-MhKZS9SONS9DKtA,49902
28
28
  bittensor_cli/src/commands/subnets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  bittensor_cli/src/commands/subnets/price.py,sha256=O8oK12hCtm1asQGx2MR1xtYA9ygkklhFtXvBON4DcGM,30069
30
- bittensor_cli/src/commands/subnets/subnets.py,sha256=EiZTUiPPRbWi8sDXVn2lVuKS89W8Ky1opeT9RpgIe1E,89534
31
- bittensor_cli-9.3.0.dist-info/METADATA,sha256=OH1bS7MqTR0KR5mn9QJUYXRui9F2QoPHgqYyRp-IKBs,6462
32
- bittensor_cli-9.3.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
33
- bittensor_cli-9.3.0.dist-info/entry_points.txt,sha256=hBTLGLbVxmAKy69XSKaUZvjTCmyEzDGZKq4S8UOto8I,49
34
- bittensor_cli-9.3.0.dist-info/top_level.txt,sha256=DvgvXpmTtI_Q1BbDZMlK90LFcGFCreN1daViEPV2iFw,14
35
- bittensor_cli-9.3.0.dist-info/RECORD,,
30
+ bittensor_cli/src/commands/subnets/subnets.py,sha256=QJuFm9UGG9EBeK9IjtBFpASV1qV6XEdz1L96Ka8zfB4,93692
31
+ bittensor_cli-9.4.1.dist-info/METADATA,sha256=Jvz2rvjzoHPj2ygRVI9GGXmSY8-q4p2PJJusejKw9Z8,6482
32
+ bittensor_cli-9.4.1.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
33
+ bittensor_cli-9.4.1.dist-info/entry_points.txt,sha256=hBTLGLbVxmAKy69XSKaUZvjTCmyEzDGZKq4S8UOto8I,49
34
+ bittensor_cli-9.4.1.dist-info/top_level.txt,sha256=DvgvXpmTtI_Q1BbDZMlK90LFcGFCreN1daViEPV2iFw,14
35
+ bittensor_cli-9.4.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.4.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5