bittensor-cli 8.4.3__py3-none-any.whl → 8.4.4__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.
bittensor_cli/__init__.py CHANGED
@@ -18,6 +18,6 @@
18
18
  from .cli import CLIManager
19
19
 
20
20
 
21
- __version__ = "8.4.3"
21
+ __version__ = "8.4.4"
22
22
 
23
23
  __all__ = ["CLIManager", "__version__"]
bittensor_cli/cli.py CHANGED
@@ -58,7 +58,7 @@ except ImportError:
58
58
  pass
59
59
 
60
60
 
61
- __version__ = "8.4.3"
61
+ __version__ = "8.4.4"
62
62
 
63
63
 
64
64
  _core_version = re.match(r"^\d+\.\d+\.\d+", __version__).group(0)
@@ -2798,7 +2798,9 @@ class CLIManager:
2798
2798
  [green]$[/green] btcli root proposals
2799
2799
  """
2800
2800
  self.verbosity_handler(quiet, verbose)
2801
- return self._run_command(root.proposals(self.initialize_chain(network)))
2801
+ return self._run_command(
2802
+ root.proposals(self.initialize_chain(network), verbose)
2803
+ )
2802
2804
 
2803
2805
  def root_set_take(
2804
2806
  self,
@@ -1010,3 +1010,32 @@ def hex_to_bytes(hex_str: str) -> bytes:
1010
1010
  else:
1011
1011
  bytes_result = bytes.fromhex(hex_str)
1012
1012
  return bytes_result
1013
+
1014
+
1015
+ def blocks_to_duration(blocks: int) -> str:
1016
+ """Convert blocks to human readable duration string using two largest units.
1017
+
1018
+ Args:
1019
+ blocks (int): Number of blocks (12s per block)
1020
+
1021
+ Returns:
1022
+ str: Duration string like '2d 5h', '3h 45m', '2m 10s', or '0s'
1023
+ """
1024
+ if blocks <= 0:
1025
+ return "0s"
1026
+
1027
+ seconds = blocks * 12
1028
+ intervals = [
1029
+ ("d", 86400), # 60 * 60 * 24
1030
+ ("h", 3600), # 60 * 60
1031
+ ("m", 60),
1032
+ ("s", 1),
1033
+ ]
1034
+ results = []
1035
+ for unit, seconds_per_unit in intervals:
1036
+ unit_count = seconds // seconds_per_unit
1037
+ seconds %= seconds_per_unit
1038
+ if unit_count > 0:
1039
+ results.append(f"{unit_count}{unit}")
1040
+ # Return only the first two non-zero units
1041
+ return " ".join(results[:2]) or "0s"
@@ -42,6 +42,7 @@ from bittensor_cli.src.bittensor.utils import (
42
42
  update_metadata_table,
43
43
  group_subnets,
44
44
  unlock_key,
45
+ blocks_to_duration,
45
46
  )
46
47
 
47
48
  if TYPE_CHECKING:
@@ -82,14 +83,22 @@ def format_call_data(call_data: dict) -> str:
82
83
  call_info = call_details[0]
83
84
  call_function, call_args = next(iter(call_info.items()))
84
85
 
85
- # Extract the argument, handling tuple values
86
- formatted_args = ", ".join(
87
- str(arg[0]) if isinstance(arg, tuple) else str(arg)
88
- for arg in call_args.values()
89
- )
86
+ # Format arguments, handle nested/large payloads
87
+ formatted_args = []
88
+ for arg_name, arg_value in call_args.items():
89
+ if isinstance(arg_value, (tuple, list, dict)):
90
+ # For large nested, show abbreviated version
91
+ content_str = str(arg_value)
92
+ if len(content_str) > 20:
93
+ formatted_args.append(f"{arg_name}: ... [{len(content_str)}] ...")
94
+ else:
95
+ formatted_args.append(f"{arg_name}: {arg_value}")
96
+ else:
97
+ formatted_args.append(f"{arg_name}: {arg_value}")
90
98
 
91
99
  # Format the final output string
92
- return f"{call_function}({formatted_args})"
100
+ args_str = ", ".join(formatted_args)
101
+ return f"{module}.{call_function}({args_str})"
93
102
 
94
103
 
95
104
  async def _get_senate_members(
@@ -1210,24 +1219,30 @@ async def register(wallet: Wallet, subtensor: SubtensorInterface, prompt: bool):
1210
1219
  )
1211
1220
 
1212
1221
 
1213
- async def proposals(subtensor: SubtensorInterface):
1222
+ async def proposals(subtensor: SubtensorInterface, verbose: bool):
1214
1223
  console.print(
1215
1224
  ":satellite: Syncing with chain: [white]{}[/white] ...".format(
1216
1225
  subtensor.network
1217
1226
  )
1218
1227
  )
1219
- print_verbose("Fetching senate members & proposals")
1220
1228
  block_hash = await subtensor.substrate.get_chain_head()
1221
- senate_members, all_proposals = await asyncio.gather(
1229
+ senate_members, all_proposals, current_block = await asyncio.gather(
1222
1230
  _get_senate_members(subtensor, block_hash),
1223
1231
  _get_proposals(subtensor, block_hash),
1232
+ subtensor.substrate.get_block_number(block_hash),
1224
1233
  )
1225
1234
 
1226
- print_verbose("Fetching member information from Chain")
1227
1235
  registered_delegate_info: dict[
1228
1236
  str, DelegatesDetails
1229
1237
  ] = await subtensor.get_delegate_identities()
1230
1238
 
1239
+ title = (
1240
+ f"[bold #4196D6]Bittensor Governance Proposals[/bold #4196D6]\n"
1241
+ f"[steel_blue3]Current Block:[/steel_blue3] {current_block}\t"
1242
+ f"[steel_blue3]Network:[/steel_blue3] {subtensor.network}\n\n"
1243
+ f"[steel_blue3]Active Proposals:[/steel_blue3] {len(all_proposals)}\t"
1244
+ f"[steel_blue3]Senate Size:[/steel_blue3] {len(senate_members)}\n"
1245
+ )
1231
1246
  table = Table(
1232
1247
  Column(
1233
1248
  "[white]HASH",
@@ -1242,8 +1257,8 @@ async def proposals(subtensor: SubtensorInterface):
1242
1257
  style="rgb(50,163,219)",
1243
1258
  ),
1244
1259
  Column("[white]END", style="bright_cyan"),
1245
- Column("[white]CALLDATA", style="dark_sea_green"),
1246
- title=f"\n[dark_orange]Proposals\t\t\nActive Proposals: {len(all_proposals)}\t\tSenate Size: {len(senate_members)}\nNetwork: {subtensor.network}",
1260
+ Column("[white]CALLDATA", style="dark_sea_green", width=30),
1261
+ title=title,
1247
1262
  show_footer=True,
1248
1263
  box=box.SIMPLE_HEAVY,
1249
1264
  pad_edge=False,
@@ -1251,16 +1266,36 @@ async def proposals(subtensor: SubtensorInterface):
1251
1266
  border_style="bright_black",
1252
1267
  )
1253
1268
  for hash_, (call_data, vote_data) in all_proposals.items():
1269
+ blocks_remaining = vote_data.end - current_block
1270
+ if blocks_remaining > 0:
1271
+ duration_str = blocks_to_duration(blocks_remaining)
1272
+ vote_end_cell = f"{vote_data.end} [dim](in {duration_str})[/dim]"
1273
+ else:
1274
+ vote_end_cell = f"{vote_data.end} [red](expired)[/red]"
1275
+
1276
+ ayes_threshold = (
1277
+ (len(vote_data.ayes) / vote_data.threshold * 100)
1278
+ if vote_data.threshold > 0
1279
+ else 0
1280
+ )
1281
+ nays_threshold = (
1282
+ (len(vote_data.nays) / vote_data.threshold * 100)
1283
+ if vote_data.threshold > 0
1284
+ else 0
1285
+ )
1254
1286
  table.add_row(
1255
- hash_,
1287
+ hash_ if verbose else f"{hash_[:4]}...{hash_[-4:]}",
1256
1288
  str(vote_data.threshold),
1257
- str(len(vote_data.ayes)),
1258
- str(len(vote_data.nays)),
1289
+ f"{len(vote_data.ayes)} ({ayes_threshold:.2f}%)",
1290
+ f"{len(vote_data.nays)} ({nays_threshold:.2f}%)",
1259
1291
  display_votes(vote_data, registered_delegate_info),
1260
- str(vote_data.end),
1292
+ vote_end_cell,
1261
1293
  format_call_data(call_data),
1262
1294
  )
1263
- return console.print(table)
1295
+ console.print(table)
1296
+ console.print(
1297
+ "\n[dim]* Both Ayes and Nays percentages are calculated relative to the proposal's threshold.[/dim]"
1298
+ )
1264
1299
 
1265
1300
 
1266
1301
  async def set_take(wallet: Wallet, subtensor: SubtensorInterface, take: float) -> bool:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bittensor-cli
3
- Version: 8.4.3
3
+ Version: 8.4.4
4
4
  Summary: Bittensor CLI
5
5
  Home-page: https://github.com/opentensor/btcli
6
6
  Author: bittensor.com
@@ -1,5 +1,5 @@
1
- bittensor_cli/__init__.py,sha256=BPag7sRvH5kJF-Fz2EwI1ZVlYOgFEdO6YHoOiRVrFiA,1217
2
- bittensor_cli/cli.py,sha256=unsfKRvxROQ7KfF6HMrp4t1DqwAl4yIUMFgIzheG8pY,170420
1
+ bittensor_cli/__init__.py,sha256=Lv2RXak408x-iJTQ2h6fQrO4dHaSiy0KNbH9-uNj24k,1217
2
+ bittensor_cli/cli.py,sha256=3yQEQjMZKqfH4uhf747UWzL4EOHXdJT6AAXufTaMm_4,170451
3
3
  bittensor_cli/doc_generation_helper.py,sha256=GexqjEIKulWg84hpNBEchJ840oOgOi7DWpt447nsdNI,91
4
4
  bittensor_cli/src/__init__.py,sha256=LpTjd5p40H08K4IbyJCNdLJhEcb8NuWXOwl5kSNYwjI,12355
5
5
  bittensor_cli/src/bittensor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -9,14 +9,14 @@ bittensor_cli/src/bittensor/chain_data.py,sha256=IsHWjmhJbTvud2i3IM1sfmBHP82VxNH
9
9
  bittensor_cli/src/bittensor/minigraph.py,sha256=17AjEA75MO7ez_NekOJSaAz6ARjPt99QG_7E1RJ_u_k,8891
10
10
  bittensor_cli/src/bittensor/networking.py,sha256=pZLMs8YXpZzDMLXWMBb_Bj6TVkm_q9khyY-lnbwVMuE,462
11
11
  bittensor_cli/src/bittensor/subtensor_interface.py,sha256=JPlA39oHf1k3ltrgDKeiAnBqF51oJnn-s3EO5y1WbAY,42669
12
- bittensor_cli/src/bittensor/utils.py,sha256=cQK2tU06OYAbedqVi3M9Nw6S2DujyyO7qHB-uAVkmDE,34686
12
+ bittensor_cli/src/bittensor/utils.py,sha256=WiQPe3cSmqQmrxrQ2IE1v2iw9-mNaia7pPunC8RB_PI,35482
13
13
  bittensor_cli/src/bittensor/extrinsics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  bittensor_cli/src/bittensor/extrinsics/registration.py,sha256=Ieh8Wo9u7km0A_1FhEdKluozcFZB0VCs1sFEQc0faQA,58851
15
15
  bittensor_cli/src/bittensor/extrinsics/root.py,sha256=hajvQOA3GyBsFKu7ifa69096dSP6NwBXmKm8HKLRVzs,19079
16
16
  bittensor_cli/src/bittensor/extrinsics/transfer.py,sha256=I0XXmLI8rTxb4kUqws0J-PPcdg38TeV8AeyIVQT-TOU,8644
17
17
  bittensor_cli/src/bittensor/templates/table.j2,sha256=P2EFiksnO1cQsB8zjK6hVJwUryHTsLslzRE0YtobAV8,10601
18
18
  bittensor_cli/src/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- bittensor_cli/src/commands/root.py,sha256=28mHTMkZe0X-62Sg6o9dG82m1bx5IAG9eXk9ZBr3Jjo,62256
19
+ bittensor_cli/src/commands/root.py,sha256=SCniGHwKTHNH1hQgHcXiM34v07KdJjpeB9YCRBrL1tw,63780
20
20
  bittensor_cli/src/commands/subnets.py,sha256=riR41_ajUVWlDoaTUQahPzZswtY2h72pMK0rNuPj2SM,33164
21
21
  bittensor_cli/src/commands/sudo.py,sha256=bP9t0QpXmqHnscEvCFHgJ4a7vETyqG1Kuc2CIVQ5qus,8436
22
22
  bittensor_cli/src/commands/wallets.py,sha256=V6Vcnt7Q3tFi02ugeIPIPF8BaraDwiIkHT3oZ-wfF7Q,60940
@@ -24,8 +24,8 @@ bittensor_cli/src/commands/weights.py,sha256=XHn0MLYUcEUtOkA_soIBJ5rqkpIliUVnyc4
24
24
  bittensor_cli/src/commands/stake/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  bittensor_cli/src/commands/stake/children_hotkeys.py,sha256=hu7ObsUkg6j6_1Bylqe3oBajV9gQmr6QlggXYTWwgjQ,28470
26
26
  bittensor_cli/src/commands/stake/stake.py,sha256=7TyFtL5wnXvGvD-GckNrNTRdcu3RewAfx_JfEekugFU,56147
27
- bittensor_cli-8.4.3.dist-info/METADATA,sha256=MgdktN35M2FjxX60ZOmWgE3gYnPDAQ_Je1Xz6M68gRk,6786
28
- bittensor_cli-8.4.3.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
29
- bittensor_cli-8.4.3.dist-info/entry_points.txt,sha256=hBTLGLbVxmAKy69XSKaUZvjTCmyEzDGZKq4S8UOto8I,49
30
- bittensor_cli-8.4.3.dist-info/top_level.txt,sha256=DvgvXpmTtI_Q1BbDZMlK90LFcGFCreN1daViEPV2iFw,14
31
- bittensor_cli-8.4.3.dist-info/RECORD,,
27
+ bittensor_cli-8.4.4.dist-info/METADATA,sha256=0Fzbs6Yt2PKxuqo7T1qU3OFHRZVlsiEOx-cJZKpf9jY,6786
28
+ bittensor_cli-8.4.4.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
29
+ bittensor_cli-8.4.4.dist-info/entry_points.txt,sha256=hBTLGLbVxmAKy69XSKaUZvjTCmyEzDGZKq4S8UOto8I,49
30
+ bittensor_cli-8.4.4.dist-info/top_level.txt,sha256=DvgvXpmTtI_Q1BbDZMlK90LFcGFCreN1daViEPV2iFw,14
31
+ bittensor_cli-8.4.4.dist-info/RECORD,,