htcli 1.1.0__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.
Files changed (140) hide show
  1. htcli-1.1.0.dist-info/METADATA +509 -0
  2. htcli-1.1.0.dist-info/RECORD +140 -0
  3. htcli-1.1.0.dist-info/WHEEL +4 -0
  4. htcli-1.1.0.dist-info/entry_points.txt +2 -0
  5. htcli-1.1.0.dist-info/licenses/LICENSE +21 -0
  6. src/__init__.py +0 -0
  7. src/htcli/__init__.py +5 -0
  8. src/htcli/client/__init__.py +338 -0
  9. src/htcli/client/extrinsics/__init__.py +26 -0
  10. src/htcli/client/extrinsics/base.py +487 -0
  11. src/htcli/client/extrinsics/consensus.py +79 -0
  12. src/htcli/client/extrinsics/governance.py +714 -0
  13. src/htcli/client/extrinsics/identity.py +490 -0
  14. src/htcli/client/extrinsics/node.py +1054 -0
  15. src/htcli/client/extrinsics/overwatch.py +401 -0
  16. src/htcli/client/extrinsics/staking.py +1504 -0
  17. src/htcli/client/extrinsics/subnet.py +2218 -0
  18. src/htcli/client/extrinsics/validator.py +203 -0
  19. src/htcli/client/extrinsics/wallet.py +323 -0
  20. src/htcli/client/offchain/__init__.py +10 -0
  21. src/htcli/client/offchain/backup.py +385 -0
  22. src/htcli/client/offchain/config.py +541 -0
  23. src/htcli/client/offchain/wallet.py +839 -0
  24. src/htcli/client/rpc/__init__.py +20 -0
  25. src/htcli/client/rpc/chain.py +568 -0
  26. src/htcli/client/rpc/node.py +783 -0
  27. src/htcli/client/rpc/overwatch.py +680 -0
  28. src/htcli/client/rpc/staking.py +216 -0
  29. src/htcli/client/rpc/subnet.py +2104 -0
  30. src/htcli/client/rpc/wallet.py +912 -0
  31. src/htcli/commands/__init__.py +31 -0
  32. src/htcli/commands/chain/__init__.py +66 -0
  33. src/htcli/commands/chain/display.py +204 -0
  34. src/htcli/commands/chain/handlers.py +260 -0
  35. src/htcli/commands/config/__init__.py +158 -0
  36. src/htcli/commands/config/display.py +353 -0
  37. src/htcli/commands/config/handlers.py +347 -0
  38. src/htcli/commands/config/prompts.py +357 -0
  39. src/htcli/commands/consensus/__init__.py +61 -0
  40. src/htcli/commands/consensus/handlers.py +100 -0
  41. src/htcli/commands/governance/__init__.py +49 -0
  42. src/htcli/commands/governance/handlers.py +81 -0
  43. src/htcli/commands/node/__init__.py +304 -0
  44. src/htcli/commands/node/display.py +749 -0
  45. src/htcli/commands/node/error_handling.py +470 -0
  46. src/htcli/commands/node/handlers.py +844 -0
  47. src/htcli/commands/node/prompts.py +346 -0
  48. src/htcli/commands/overwatch/__init__.py +219 -0
  49. src/htcli/commands/overwatch/display.py +396 -0
  50. src/htcli/commands/overwatch/error_handling.py +276 -0
  51. src/htcli/commands/overwatch/handlers.py +443 -0
  52. src/htcli/commands/overwatch/prompts.py +359 -0
  53. src/htcli/commands/stake/__init__.py +736 -0
  54. src/htcli/commands/stake/display.py +1103 -0
  55. src/htcli/commands/stake/error_handling.py +425 -0
  56. src/htcli/commands/stake/handlers.py +1902 -0
  57. src/htcli/commands/stake/prompts.py +1080 -0
  58. src/htcli/commands/subnet/__init__.py +639 -0
  59. src/htcli/commands/subnet/display.py +801 -0
  60. src/htcli/commands/subnet/error_handling.py +524 -0
  61. src/htcli/commands/subnet/handlers.py +2855 -0
  62. src/htcli/commands/subnet/prompts.py +1225 -0
  63. src/htcli/commands/validator/__init__.py +192 -0
  64. src/htcli/commands/validator/display.py +54 -0
  65. src/htcli/commands/validator/handlers.py +340 -0
  66. src/htcli/commands/wallet/__init__.py +546 -0
  67. src/htcli/commands/wallet/display.py +806 -0
  68. src/htcli/commands/wallet/error_handling.py +210 -0
  69. src/htcli/commands/wallet/handlers.py +3040 -0
  70. src/htcli/commands/wallet/prompts.py +1518 -0
  71. src/htcli/config.py +184 -0
  72. src/htcli/dependencies.py +186 -0
  73. src/htcli/errors/__init__.py +63 -0
  74. src/htcli/errors/base.py +141 -0
  75. src/htcli/errors/display.py +20 -0
  76. src/htcli/errors/handlers.py +710 -0
  77. src/htcli/main.py +343 -0
  78. src/htcli/models/__init__.py +21 -0
  79. src/htcli/models/enums/enum_types.py +35 -0
  80. src/htcli/models/errors.py +103 -0
  81. src/htcli/models/requests/__init__.py +197 -0
  82. src/htcli/models/requests/config.py +70 -0
  83. src/htcli/models/requests/consensus.py +19 -0
  84. src/htcli/models/requests/governance.py +38 -0
  85. src/htcli/models/requests/identity.py +51 -0
  86. src/htcli/models/requests/key.py +22 -0
  87. src/htcli/models/requests/node.py +91 -0
  88. src/htcli/models/requests/overwatch.py +64 -0
  89. src/htcli/models/requests/staking.py +580 -0
  90. src/htcli/models/requests/subnet.py +195 -0
  91. src/htcli/models/requests/validator.py +139 -0
  92. src/htcli/models/requests/wallet.py +118 -0
  93. src/htcli/models/responses/__init__.py +147 -0
  94. src/htcli/models/responses/base.py +18 -0
  95. src/htcli/models/responses/chain.py +39 -0
  96. src/htcli/models/responses/config.py +58 -0
  97. src/htcli/models/responses/identity.py +102 -0
  98. src/htcli/models/responses/overwatch.py +51 -0
  99. src/htcli/models/responses/staking.py +502 -0
  100. src/htcli/models/responses/subnet.py +856 -0
  101. src/htcli/models/responses/wallet.py +185 -0
  102. src/htcli/ui/__init__.py +87 -0
  103. src/htcli/ui/colors.py +309 -0
  104. src/htcli/ui/components/__init__.py +60 -0
  105. src/htcli/ui/components/panels.py +174 -0
  106. src/htcli/ui/components/progress.py +166 -0
  107. src/htcli/ui/components/spinners.py +92 -0
  108. src/htcli/ui/components/tables.py +809 -0
  109. src/htcli/ui/components/trees.py +721 -0
  110. src/htcli/ui/display.py +336 -0
  111. src/htcli/ui/prompts.py +870 -0
  112. src/htcli/utils/__init__.py +76 -0
  113. src/htcli/utils/blockchain/__init__.py +75 -0
  114. src/htcli/utils/blockchain/formatting.py +368 -0
  115. src/htcli/utils/blockchain/patches.py +286 -0
  116. src/htcli/utils/blockchain/peer_id.py +186 -0
  117. src/htcli/utils/blockchain/staking.py +448 -0
  118. src/htcli/utils/blockchain/type_registry.py +1373 -0
  119. src/htcli/utils/blockchain/validation.py +179 -0
  120. src/htcli/utils/cache.py +613 -0
  121. src/htcli/utils/constants.py +38 -0
  122. src/htcli/utils/legacy/__init__.py +12 -0
  123. src/htcli/utils/legacy/colors.py +311 -0
  124. src/htcli/utils/legacy/crypto.py +1176 -0
  125. src/htcli/utils/legacy/formatting.py +452 -0
  126. src/htcli/utils/legacy/interactive.py +306 -0
  127. src/htcli/utils/legacy/subnet_manifest.py +265 -0
  128. src/htcli/utils/legacy/validation.py +488 -0
  129. src/htcli/utils/logging.py +183 -0
  130. src/htcli/utils/network/__init__.py +20 -0
  131. src/htcli/utils/network/subnet.py +344 -0
  132. src/htcli/utils/prompts.py +27 -0
  133. src/htcli/utils/scale_codec.py +155 -0
  134. src/htcli/utils/validation/__init__.py +57 -0
  135. src/htcli/utils/validation/prompt_validators.py +267 -0
  136. src/htcli/utils/wallet/__init__.py +65 -0
  137. src/htcli/utils/wallet/auth.py +151 -0
  138. src/htcli/utils/wallet/core.py +1069 -0
  139. src/htcli/utils/wallet/crypto.py +1615 -0
  140. src/htcli/utils/wallet/migration.py +159 -0
@@ -0,0 +1,174 @@
1
+ """
2
+ HTCLI panel components.
3
+ Provides enhanced panels for content display.
4
+ """
5
+
6
+ from typing import Any, Optional
7
+
8
+ from rich.layout import Layout
9
+ from rich.live import Live
10
+ from rich.panel import Panel
11
+
12
+ from ..colors import HTCLIColors
13
+ from ..display import get_console
14
+
15
+
16
+ class HTCLIPanel:
17
+ """Enhanced panel for HTCLI operations."""
18
+
19
+ def __init__(
20
+ self,
21
+ content: Any,
22
+ title: str = None,
23
+ border_style: str = "htcli.panel.border",
24
+ padding: tuple = (1, 2),
25
+ expand: bool = True,
26
+ highlight: bool = False,
27
+ ):
28
+ self.panel = Panel(
29
+ content,
30
+ title=title,
31
+ border_style=border_style,
32
+ padding=padding,
33
+ expand=expand,
34
+ highlight=highlight,
35
+ )
36
+
37
+ @classmethod
38
+ def info_panel(cls, content: Any, title: str = "ℹ️ Information"):
39
+ """Create an info panel."""
40
+ return cls(
41
+ content,
42
+ title=title,
43
+ border_style="blue",
44
+ padding=(1, 2),
45
+ )
46
+
47
+ @classmethod
48
+ def success_panel(cls, content: Any, title: str = "✅ Success"):
49
+ """Create a success panel."""
50
+ return cls(
51
+ content,
52
+ title=title,
53
+ border_style="green",
54
+ padding=(1, 2),
55
+ )
56
+
57
+ @classmethod
58
+ def warning_panel(cls, content: Any, title: str = "⚠️ Warning"):
59
+ """Create a warning panel."""
60
+ return cls(
61
+ content,
62
+ title=title,
63
+ border_style="yellow",
64
+ padding=(1, 2),
65
+ )
66
+
67
+ @classmethod
68
+ def error_panel(cls, content: Any, title: str = "❌ Error"):
69
+ """Create an error panel."""
70
+ return cls(
71
+ content,
72
+ title=title,
73
+ border_style="red",
74
+ padding=(1, 2),
75
+ )
76
+
77
+ def render(self, console=None):
78
+ """Render the panel."""
79
+ if console is None:
80
+ console_instance = get_console()
81
+ # HTCLIConsole exposes `print`
82
+ console_instance.print(self.panel)
83
+ return
84
+
85
+ # Support both HTCLIConsole and raw Rich Console objects
86
+ if hasattr(console, "print"):
87
+ console.print(self.panel)
88
+ elif hasattr(console, "console") and hasattr(console.console, "print"):
89
+ console.console.print(self.panel)
90
+ else:
91
+ # Fallback to global console if provided object is unexpected
92
+ get_console().print(self.panel)
93
+
94
+ def __rich__(self):
95
+ """Rich renderable."""
96
+ return self.panel
97
+
98
+
99
+ class HTCLIStatus:
100
+ """Real-time status display for HTCLI operations."""
101
+
102
+ def __init__(self, title: str = "Status"):
103
+ self.title = title
104
+ self.layout = Layout()
105
+ self.layout.split_column(
106
+ Layout(name="header", size=3),
107
+ Layout(name="main", size=10),
108
+ Layout(name="footer", size=3),
109
+ )
110
+ self.layout["header"].update(Panel(title, style="bold cyan"))
111
+ self.layout["footer"].update(Panel("", style="dim"))
112
+
113
+ def update_main(self, content: Any):
114
+ """Update the main content area."""
115
+ self.layout["main"].update(content)
116
+
117
+ def update_footer(self, content: Any):
118
+ """Update the footer area."""
119
+ self.layout["footer"].update(content)
120
+
121
+ def render(self):
122
+ """Render the status display."""
123
+ console = get_console()
124
+ console.print(self.layout)
125
+
126
+ def __rich__(self):
127
+ """Rich renderable."""
128
+ return self.layout
129
+
130
+
131
+ # Specialized panel factory functions
132
+ def create_welcome_panel() -> HTCLIPanel:
133
+ """Create a welcome panel."""
134
+ welcome_text = """
135
+ Welcome to HTCLI - Your Gateway to the Hypertensor Blockchain
136
+
137
+ 🌐 Manage subnets and nodes
138
+ 💰 Handle wallets and transactions
139
+ 📊 Monitor network statistics
140
+ ⚡ Execute blockchain operations
141
+
142
+ Use 'htcli --help' to see all available commands.
143
+ """
144
+ return HTCLIPanel.info_panel(welcome_text, "🚀 HTCLI Welcome")
145
+
146
+
147
+ def create_help_panel() -> HTCLIPanel:
148
+ """Create a help panel."""
149
+ help_text = """
150
+ Available Commands:
151
+
152
+ 📊 subnet - Subnet management operations
153
+ 💰 wallet - Wallet and key management
154
+ 📡 node - Node registration and management
155
+ ⚡ stake - Staking operations
156
+ 🔗 chain - Chain information and statistics
157
+ ⚙️ config - Configuration management
158
+
159
+ For detailed help on any command, use:
160
+ htcli <command> --help
161
+ """
162
+ return HTCLIPanel.info_panel(help_text, "📚 HTCLI Help")
163
+
164
+
165
+ def create_error_summary_panel(errors: list[str]) -> HTCLIPanel:
166
+ """Create an error summary panel."""
167
+ error_text = "\n".join([f"• {error}" for error in errors])
168
+ return HTCLIPanel.error_panel(error_text, "❌ Errors Found")
169
+
170
+
171
+ def create_success_summary_panel(successes: list[str]) -> HTCLIPanel:
172
+ """Create a success summary panel."""
173
+ success_text = "\n".join([f"✅ {success}" for success in successes])
174
+ return HTCLIPanel.success_panel(success_text, "🎉 Operations Completed")
@@ -0,0 +1,166 @@
1
+ """
2
+ HTCLI progress components.
3
+ Provides enhanced progress bars for operations.
4
+ """
5
+
6
+ from contextlib import contextmanager
7
+ from typing import Any, Optional, Union
8
+
9
+ from rich.console import Console
10
+ from rich.progress import (
11
+ BarColumn,
12
+ Progress,
13
+ SpinnerColumn,
14
+ TaskID,
15
+ TaskProgressColumn,
16
+ TextColumn,
17
+ TimeRemainingColumn,
18
+ )
19
+
20
+ from ..display import get_console
21
+
22
+
23
+ class HTCLIProgress:
24
+ """Enhanced progress bar for HTCLI operations."""
25
+
26
+ def __init__(
27
+ self,
28
+ console: Console = None,
29
+ refresh_per_second: float = 10,
30
+ transient: bool = False,
31
+ ):
32
+ # Use the provided console or get the default one
33
+ # Rich Progress uses Live display internally which handles line updates automatically
34
+ # The SpinnerColumn will automatically animate while the progress bar updates
35
+ if console is None:
36
+ console = get_console().console
37
+
38
+ self.console = console
39
+ # SpinnerColumn animates automatically - refresh_per_second controls animation speed
40
+ # Higher refresh rate = smoother spinner animation
41
+ self.progress = Progress(
42
+ SpinnerColumn(), # Spinner animates automatically while progress updates
43
+ TextColumn("[progress.description]{task.description}"),
44
+ BarColumn(
45
+ bar_width=None,
46
+ style="htcli.progress.bar",
47
+ complete_style="htcli.status.success",
48
+ finished_style="htcli.status.success",
49
+ ),
50
+ TaskProgressColumn(),
51
+ TimeRemainingColumn(),
52
+ console=self.console,
53
+ transient=transient, # Allow control over whether progress disappears after completion
54
+ refresh_per_second=refresh_per_second, # Controls spinner animation speed
55
+ # Ensure progress is visible even for quick operations
56
+ auto_refresh=True,
57
+ )
58
+ self._tasks: dict[str, TaskID] = {}
59
+ self._running = False
60
+
61
+ def __enter__(self):
62
+ self._running = True
63
+ self.progress.start()
64
+ return self
65
+
66
+ def __exit__(self, exc_type, exc_val, exc_tb):
67
+ self._running = False
68
+ # Stop the progress display - this cleans up the Live display
69
+ self.progress.stop()
70
+ # Print a newline to ensure clean separation from progress bar output
71
+ # This prevents the next output from appearing on the same line as the progress bar
72
+ self.console.print()
73
+
74
+ def add_task(
75
+ self, description: str, total: Optional[float] = None, task_id: str = None
76
+ ) -> TaskID:
77
+ """Add a new task to the progress bar."""
78
+ if task_id is None:
79
+ task_id = description
80
+ task = self.progress.add_task(description, total=total)
81
+ self._tasks[task_id] = task
82
+ return task
83
+
84
+ def update(
85
+ self,
86
+ task_id: Union[TaskID, str],
87
+ advance: float = 1,
88
+ description: str = None,
89
+ total: float = None,
90
+ ):
91
+ """Update a task's progress."""
92
+ if isinstance(task_id, str):
93
+ task_id = self._tasks.get(task_id)
94
+ if task_id is not None:
95
+ self.progress.update(
96
+ task_id, advance=advance, description=description, total=total
97
+ )
98
+
99
+ def set_description(self, task_id: Union[TaskID, str], description: str):
100
+ """Set task description."""
101
+ if isinstance(task_id, str):
102
+ task_id = self._tasks.get(task_id)
103
+ if task_id is not None:
104
+ self.progress.update(task_id, description=description)
105
+
106
+ def complete_task(self, task_id: Union[TaskID, str]):
107
+ """Mark a task as completed."""
108
+ if isinstance(task_id, str):
109
+ task_id = self._tasks.get(task_id)
110
+ if task_id is not None:
111
+ self.progress.update(task_id, completed=True)
112
+
113
+ @contextmanager
114
+ def task(
115
+ self, description: str, total: Optional[float] = None, task_id: str = None
116
+ ):
117
+ """Context manager for individual tasks."""
118
+ task = self.add_task(description, total, task_id)
119
+ try:
120
+ yield task
121
+ finally:
122
+ self.complete_task(task)
123
+
124
+
125
+ class HTCLILoadingContext:
126
+ """Context manager for loading operations with spinner indication.
127
+
128
+ Uses HTCLISpinner for indeterminate loading operations (no known completion).
129
+ This ensures the spinner updates in place on the same line rather than
130
+ printing multiple lines.
131
+ """
132
+
133
+ def __init__(
134
+ self,
135
+ message: str = "Loading...",
136
+ show_progress: bool = True,
137
+ transient: bool = True,
138
+ ):
139
+ self.message = message
140
+ self.show_progress = show_progress
141
+ self.transient = transient
142
+ self.spinner = None
143
+
144
+ def __enter__(self):
145
+ if self.show_progress:
146
+ # Use HTCLISpinner for simple loading operations
147
+ # This properly uses Rich's Live display to update in place
148
+ from .spinners import HTCLISpinner
149
+
150
+ self.spinner = HTCLISpinner(
151
+ text=self.message,
152
+ spinner="dots",
153
+ transient=self.transient,
154
+ refresh_per_second=12,
155
+ )
156
+ self.spinner.__enter__()
157
+ return self
158
+
159
+ def __exit__(self, exc_type, exc_val, exc_tb):
160
+ if self.spinner:
161
+ self.spinner.__exit__(exc_type, exc_val, exc_tb)
162
+
163
+ def update_message(self, message: str):
164
+ """Update the loading message."""
165
+ if self.spinner:
166
+ self.spinner.update(message)
@@ -0,0 +1,92 @@
1
+ """
2
+ HTCLI spinner components.
3
+ Provides enhanced spinners for loading operations.
4
+ """
5
+
6
+ from contextlib import contextmanager
7
+
8
+ from rich.live import Live
9
+ from rich.spinner import Spinner
10
+ from rich.text import Text
11
+
12
+ from ..display import get_console
13
+
14
+
15
+ class HTCLISpinner:
16
+ """Enhanced spinner for HTCLI operations using Rich's Spinner with Live display."""
17
+
18
+ def __init__(
19
+ self,
20
+ text: str = "Loading...",
21
+ spinner: str = "dots",
22
+ style: str = "htcli.spinner",
23
+ refresh_per_second: float = 12,
24
+ transient: bool = True,
25
+ ):
26
+ # Get console and ensure it's configured for terminal output
27
+ base_console = get_console().console
28
+ # Create a console instance specifically for the Live display
29
+ # This ensures proper terminal detection and in-place updates
30
+ self.console = base_console
31
+ self.text = text
32
+ self.spinner_name = spinner
33
+ self.style = style
34
+ self.refresh_per_second = refresh_per_second
35
+ self.transient = transient
36
+ self._spinner = None
37
+ self._live = None
38
+ self._running = False
39
+
40
+ def __enter__(self):
41
+ # Create Rich Spinner with text
42
+ self._spinner = Spinner(
43
+ name=self.spinner_name,
44
+ text=Text(self.text, style=self.style),
45
+ speed=1.0,
46
+ )
47
+ # Create Live display with the spinner
48
+ # For in-place updates (spinning on the same line), we need:
49
+ # - screen=False: Update on the same line using carriage return
50
+ # - auto_refresh=True: Automatically refresh the display
51
+ # - console must be a terminal (not a file/pipe)
52
+ # If the console is not a terminal, Live will print new lines instead of updating in place
53
+ import sys
54
+ # Only use in-place updates if stdout is a terminal
55
+ # Otherwise, fall back to simple printing (though this shouldn't happen in normal CLI usage)
56
+ is_terminal = sys.stdout.isatty() and self.console.is_terminal
57
+
58
+ self._live = Live(
59
+ self._spinner,
60
+ console=self.console,
61
+ refresh_per_second=self.refresh_per_second,
62
+ transient=self.transient,
63
+ screen=False, # Update in place on same line (uses \r carriage return)
64
+ auto_refresh=True,
65
+ vertical_overflow="visible",
66
+ )
67
+ self._running = True
68
+ self._live.start()
69
+ return self
70
+
71
+ def __exit__(self, exc_type, exc_val, exc_tb):
72
+ self._running = False
73
+ if self._live:
74
+ self._live.stop()
75
+ # Always add a newline after stopping spinner to avoid next output
76
+ # appearing on the same line as the spinner.
77
+ self.console.print()
78
+
79
+ def update(self, text: str):
80
+ """Update the spinner text and render it."""
81
+ if self._spinner and self._running:
82
+ self._spinner.update(text=Text(text, style=self.style))
83
+
84
+ @contextmanager
85
+ def step(self, step_text: str):
86
+ """Context manager for individual steps."""
87
+ original_text = self.text
88
+ self.update(f"{original_text} - {step_text}")
89
+ try:
90
+ yield
91
+ finally:
92
+ self.update(original_text)