hippius 0.2.2__py3-none-any.whl → 0.2.3__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.
@@ -0,0 +1,602 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Command Line Interface argument parser for Hippius SDK.
4
+
5
+ This module provides the argument parsing functionality for the Hippius CLI,
6
+ defining all available commands, subcommands, and their respective arguments.
7
+ """
8
+
9
+ import argparse
10
+
11
+ from hippius_sdk import get_config_value
12
+
13
+
14
+ def get_default_address():
15
+ """Get the default address for read-only operations"""
16
+ from hippius_sdk import load_config
17
+
18
+ config = load_config()
19
+ return config["substrate"].get("default_address")
20
+
21
+
22
+ def create_parser() -> argparse.ArgumentParser:
23
+ """Create and configure the argument parser for the CLI."""
24
+ # Import custom help action that shows the logo
25
+ from hippius_sdk.cli_rich import RichHelpAction
26
+
27
+ # Set up the argument parser
28
+ parser = argparse.ArgumentParser(
29
+ description="Hippius SDK Command Line Interface",
30
+ formatter_class=argparse.RawDescriptionHelpFormatter,
31
+ add_help=False, # Disable the default help action
32
+ epilog="""
33
+ examples:
34
+ # Store a file
35
+ hippius store example.txt
36
+
37
+ # Store a directory
38
+ hippius store-dir ./my_directory
39
+
40
+ # Download a file
41
+ hippius download QmHash output.txt
42
+
43
+ # Check if a CID exists
44
+ hippius exists QmHash
45
+
46
+ # View the content of a CID
47
+ hippius cat QmHash
48
+
49
+ # View your available credits
50
+ hippius credits
51
+
52
+ # View your stored files
53
+ hippius files
54
+
55
+ # View all miners for stored files
56
+ hippius files --all-miners
57
+
58
+ # Check file pinning status
59
+ hippius pinning-status
60
+
61
+ # Erasure code a file (Reed-Solomon)
62
+ hippius erasure-code large_file.mp4 --k 3 --m 5
63
+
64
+ # Erasure code without publishing to global IPFS network
65
+ hippius erasure-code large_file.avi --no-publish
66
+
67
+ # Reconstruct an erasure-coded file
68
+ hippius reconstruct QmMetadataHash reconstructed_file.mp4
69
+
70
+ # Delete a file from IPFS and marketplace
71
+ hippius delete QmHash
72
+
73
+ # Delete an erasure-coded file and all its chunks
74
+ hippius ec-delete QmMetadataHash
75
+ """,
76
+ )
77
+
78
+ # Add our custom help option
79
+ parser.add_argument(
80
+ "-h", "--help", action=RichHelpAction, help="Show this help message and exit"
81
+ )
82
+
83
+ # Optional arguments for all commands
84
+ parser.add_argument(
85
+ "--gateway",
86
+ default=get_config_value("ipfs", "gateway", "https://get.hippius.network"),
87
+ help="IPFS gateway URL for downloads (default: from config or https://get.hippius.network)",
88
+ )
89
+ parser.add_argument(
90
+ "--api-url",
91
+ default=get_config_value("ipfs", "api_url", "https://store.hippius.network"),
92
+ help="IPFS API URL for uploads (default: from config or https://store.hippius.network)",
93
+ )
94
+ parser.add_argument(
95
+ "--local-ipfs",
96
+ action="store_true",
97
+ default=get_config_value("ipfs", "local_ipfs", False),
98
+ help="Use local IPFS node (http://localhost:5001) instead of remote API",
99
+ )
100
+ parser.add_argument(
101
+ "--substrate-url",
102
+ default=get_config_value("substrate", "url", "wss://rpc.hippius.network"),
103
+ help="Substrate node WebSocket URL (default: from config or wss://rpc.hippius.network)",
104
+ )
105
+ parser.add_argument(
106
+ "--miner-ids",
107
+ help="Comma-separated list of miner IDs for storage (default: from config)",
108
+ )
109
+ parser.add_argument(
110
+ "--verbose",
111
+ "-v",
112
+ action="store_true",
113
+ default=get_config_value("cli", "verbose", False),
114
+ help="Enable verbose debug output",
115
+ )
116
+ parser.add_argument(
117
+ "--encrypt",
118
+ action="store_true",
119
+ help="Encrypt files when uploading (overrides default)",
120
+ )
121
+ parser.add_argument(
122
+ "--no-encrypt",
123
+ action="store_true",
124
+ help="Do not encrypt files when uploading (overrides default)",
125
+ )
126
+ parser.add_argument(
127
+ "--decrypt",
128
+ action="store_true",
129
+ help="Decrypt files when downloading (overrides default)",
130
+ )
131
+ parser.add_argument(
132
+ "--no-decrypt",
133
+ action="store_true",
134
+ help="Do not decrypt files when downloading (overrides default)",
135
+ )
136
+ parser.add_argument(
137
+ "--encryption-key",
138
+ help="Base64-encoded encryption key (overrides HIPPIUS_ENCRYPTION_KEY in .env)",
139
+ )
140
+ parser.add_argument(
141
+ "--password",
142
+ help="Password to decrypt the seed phrase if needed (will prompt if required and not provided)",
143
+ )
144
+ parser.add_argument(
145
+ "--account",
146
+ help="Account name to use (uses active account if not specified)",
147
+ )
148
+
149
+ # Subcommands
150
+ subparsers = parser.add_subparsers(dest="command", help="Commands")
151
+
152
+ # Add all command parsers
153
+ add_file_commands(subparsers)
154
+ add_storage_commands(subparsers)
155
+ add_market_commands(subparsers)
156
+ add_erasure_coding_commands(subparsers)
157
+ add_config_commands(subparsers)
158
+ add_seed_commands(subparsers)
159
+ add_account_commands(subparsers)
160
+ add_address_commands(subparsers)
161
+
162
+ return parser
163
+
164
+
165
+ def add_file_commands(subparsers):
166
+ """Add file operation commands to the parser."""
167
+ # Download command
168
+ download_parser = subparsers.add_parser(
169
+ "download", help="Download a file from IPFS"
170
+ )
171
+ download_parser.add_argument("cid", help="CID of file to download")
172
+ download_parser.add_argument("output_path", help="Path to save downloaded file")
173
+
174
+ # Exists command
175
+ exists_parser = subparsers.add_parser(
176
+ "exists", help="Check if a CID exists on IPFS"
177
+ )
178
+ exists_parser.add_argument("cid", help="CID to check")
179
+
180
+ # Cat command
181
+ cat_parser = subparsers.add_parser(
182
+ "cat", help="Display content of a file from IPFS"
183
+ )
184
+ cat_parser.add_argument("cid", help="CID of file to display")
185
+ cat_parser.add_argument(
186
+ "--max-size",
187
+ type=int,
188
+ default=1024,
189
+ help="Maximum number of bytes to display (default: 1024)",
190
+ )
191
+
192
+
193
+ def add_storage_commands(subparsers):
194
+ """Add storage commands to the parser."""
195
+ # Store command (upload to IPFS then store on Substrate)
196
+ store_parser = subparsers.add_parser(
197
+ "store", help="Upload a file to IPFS and store it on Substrate"
198
+ )
199
+ store_parser.add_argument("file_path", help="Path to file to upload")
200
+
201
+ # Store directory command
202
+ store_dir_parser = subparsers.add_parser(
203
+ "store-dir", help="Upload a directory to IPFS and store all files on Substrate"
204
+ )
205
+ store_dir_parser.add_argument("dir_path", help="Path to directory to upload")
206
+
207
+ # Pinning status command
208
+ pinning_status_parser = subparsers.add_parser(
209
+ "pinning-status", help="Check the status of file pinning requests"
210
+ )
211
+ pinning_status_parser.add_argument(
212
+ "--account_address",
213
+ help="Substrate account to view pins for (defaults to your keyfile account)",
214
+ )
215
+ pinning_status_parser.add_argument(
216
+ "--no-contents",
217
+ action="store_true",
218
+ help="Don't fetch additional content info for pins",
219
+ )
220
+
221
+ # Delete command
222
+ delete_parser = subparsers.add_parser(
223
+ "delete",
224
+ help="Delete a file from IPFS and cancel its storage on the blockchain",
225
+ )
226
+ delete_parser.add_argument("cid", help="CID of file to delete")
227
+ delete_parser.add_argument(
228
+ "--force",
229
+ action="store_true",
230
+ help="Delete without confirmation prompt",
231
+ )
232
+
233
+ # Keygen command
234
+ keygen_parser = subparsers.add_parser(
235
+ "keygen", help="Generate an encryption key for secure file storage"
236
+ )
237
+ keygen_parser.add_argument(
238
+ "--save",
239
+ action="store_true",
240
+ help="Save the generated key to the configuration",
241
+ )
242
+ keygen_parser.add_argument(
243
+ "--copy",
244
+ action="store_true",
245
+ help="Copy the key to clipboard (requires pyperclip)",
246
+ )
247
+
248
+
249
+ def add_market_commands(subparsers):
250
+ """Add marketplace commands to the parser."""
251
+ # Credits command
252
+ credits_parser = subparsers.add_parser(
253
+ "credits", help="Check free credits for an account in the marketplace"
254
+ )
255
+ credits_parser.add_argument(
256
+ "account_address",
257
+ nargs="?",
258
+ default=None,
259
+ help="Substrate account address (uses keypair address if not specified)",
260
+ )
261
+
262
+ # Files command
263
+ files_parser = subparsers.add_parser(
264
+ "files", help="View files stored by you or another account"
265
+ )
266
+ files_parser.add_argument(
267
+ "--account_address",
268
+ help="Substrate account to view files for (defaults to your keyfile account)",
269
+ )
270
+ files_parser.add_argument(
271
+ "--all-miners",
272
+ action="store_true",
273
+ help="Show all miners for each file",
274
+ )
275
+
276
+ files_parser.add_argument(
277
+ "cid",
278
+ help="CID to filter on",
279
+ default=None,
280
+ nargs="?",
281
+ )
282
+
283
+
284
+ def add_erasure_coding_commands(subparsers):
285
+ """Add erasure coding commands to the parser."""
286
+ # Erasure coded files command
287
+ ec_files_parser = subparsers.add_parser(
288
+ "ec-files", help="View erasure-coded files stored by you or another account"
289
+ )
290
+ ec_files_parser.add_argument(
291
+ "--account_address",
292
+ help="Substrate account to view EC files for (defaults to your keyfile account)",
293
+ )
294
+ ec_files_parser.add_argument(
295
+ "--all-miners",
296
+ action="store_true",
297
+ help="Show all miners for each chunk",
298
+ )
299
+ ec_files_parser.add_argument(
300
+ "--show-chunks",
301
+ action="store_true",
302
+ help="Show individual chunks for each file",
303
+ )
304
+
305
+ ec_files_parser.add_argument(
306
+ "cid",
307
+ help="CID to filter on",
308
+ default=None,
309
+ nargs="?",
310
+ )
311
+
312
+ # EC Delete command
313
+ ec_delete_parser = subparsers.add_parser(
314
+ "ec-delete", help="Delete an erasure-coded file and all its chunks"
315
+ )
316
+ ec_delete_parser.add_argument(
317
+ "metadata_cid", help="Metadata CID of the erasure-coded file to delete"
318
+ )
319
+ ec_delete_parser.add_argument(
320
+ "--force",
321
+ action="store_true",
322
+ help="Delete without confirmation prompt",
323
+ )
324
+
325
+ # Erasure code command
326
+ erasure_code_parser = subparsers.add_parser(
327
+ "erasure-code", help="Erasure code a file"
328
+ )
329
+ erasure_code_parser.add_argument("file_path", help="Path to file to erasure code")
330
+ erasure_code_parser.add_argument(
331
+ "--k",
332
+ type=int,
333
+ default=3,
334
+ help="Number of chunks needed for reconstruction (default: 3)",
335
+ )
336
+ erasure_code_parser.add_argument(
337
+ "--m",
338
+ type=int,
339
+ default=5,
340
+ help="Total number of chunks to create (default: 5)",
341
+ )
342
+ erasure_code_parser.add_argument(
343
+ "--chunk-size",
344
+ type=int,
345
+ default=10,
346
+ help="Chunk size in MB (default: 10)",
347
+ )
348
+ erasure_code_parser.add_argument(
349
+ "--no-publish",
350
+ action="store_true",
351
+ help="Don't publish to the global IPFS network",
352
+ )
353
+
354
+ # Reconstruct command
355
+ reconstruct_parser = subparsers.add_parser(
356
+ "reconstruct", help="Reconstruct an erasure-coded file"
357
+ )
358
+ reconstruct_parser.add_argument(
359
+ "metadata_cid", help="Metadata CID of the erasure-coded file"
360
+ )
361
+ reconstruct_parser.add_argument(
362
+ "output_file", help="Path to save the reconstructed file"
363
+ )
364
+
365
+
366
+ def add_config_commands(subparsers):
367
+ """Add configuration commands to the parser."""
368
+ # Config command
369
+ config_parser = subparsers.add_parser(
370
+ "config", help="Manage Hippius SDK configuration"
371
+ )
372
+ config_subparsers = config_parser.add_subparsers(
373
+ dest="config_action", help="Configuration action"
374
+ )
375
+
376
+ # Get configuration value
377
+ get_parser = config_subparsers.add_parser("get", help="Get a configuration value")
378
+ get_parser.add_argument(
379
+ "section",
380
+ help="Configuration section (ipfs, substrate, encryption, erasure_coding, cli)",
381
+ )
382
+ get_parser.add_argument("key", help="Configuration key")
383
+
384
+ # Set configuration value
385
+ set_parser = config_subparsers.add_parser("set", help="Set a configuration value")
386
+ set_parser.add_argument(
387
+ "section",
388
+ help="Configuration section (ipfs, substrate, encryption, erasure_coding, cli)",
389
+ )
390
+ set_parser.add_argument("key", help="Configuration key")
391
+ set_parser.add_argument("value", help="Configuration value")
392
+
393
+ # List configuration
394
+ config_subparsers.add_parser("list", help="List all configuration values")
395
+
396
+ # Reset configuration to defaults
397
+ config_subparsers.add_parser("reset", help="Reset configuration to default values")
398
+
399
+ # Import config from .env
400
+ config_subparsers.add_parser(
401
+ "import-env", help="Import configuration from .env file"
402
+ )
403
+
404
+
405
+ def add_seed_commands(subparsers):
406
+ """Add seed phrase commands to the parser."""
407
+ # Seed command
408
+ seed_parser = subparsers.add_parser("seed", help="Manage substrate seed phrase")
409
+ seed_subparsers = seed_parser.add_subparsers(
410
+ dest="seed_action", help="Seed phrase action"
411
+ )
412
+
413
+ # Set seed phrase
414
+ set_seed_parser = seed_subparsers.add_parser(
415
+ "set", help="Set the substrate seed phrase"
416
+ )
417
+ set_seed_parser.add_argument(
418
+ "seed_phrase", help="Substrate seed phrase (12 or 24 words)"
419
+ )
420
+ set_seed_parser.add_argument(
421
+ "--encode",
422
+ action="store_true",
423
+ help="Encrypt the seed phrase with a password",
424
+ )
425
+ set_seed_parser.add_argument(
426
+ "--account",
427
+ help="Account name to use (uses default if not specified)",
428
+ )
429
+
430
+ # Encode seed phrase
431
+ encode_seed_parser = seed_subparsers.add_parser(
432
+ "encode", help="Encrypt the existing seed phrase"
433
+ )
434
+ encode_seed_parser.add_argument(
435
+ "--account",
436
+ help="Account name to use (uses default if not specified)",
437
+ )
438
+
439
+ # Decode seed phrase
440
+ decode_seed_parser = seed_subparsers.add_parser(
441
+ "decode", help="Temporarily decrypt and display the seed phrase"
442
+ )
443
+ decode_seed_parser.add_argument(
444
+ "--account",
445
+ help="Account name to use (uses default if not specified)",
446
+ )
447
+
448
+ # Status seed phrase
449
+ status_seed_parser = seed_subparsers.add_parser(
450
+ "status", help="Check the status of the configured seed phrase"
451
+ )
452
+ status_seed_parser.add_argument(
453
+ "--account",
454
+ help="Account name to check (uses default if not specified)",
455
+ )
456
+
457
+
458
+ def add_account_commands(subparsers):
459
+ """Add account management commands to the parser."""
460
+ # Account command
461
+ account_parser = subparsers.add_parser("account", help="Manage substrate accounts")
462
+ account_subparsers = account_parser.add_subparsers(
463
+ dest="account_action", help="Account action"
464
+ )
465
+
466
+ # List accounts
467
+ account_subparsers.add_parser("list", help="List all accounts")
468
+
469
+ # Create account
470
+ create_account_parser = account_subparsers.add_parser(
471
+ "create", help="Create a new account with a generated seed phrase"
472
+ )
473
+ create_account_parser.add_argument(
474
+ "--name",
475
+ required=True,
476
+ help="Name for the new account",
477
+ )
478
+ create_account_parser.add_argument(
479
+ "--encrypt",
480
+ action="store_true",
481
+ help="Encrypt the seed phrase with a password",
482
+ )
483
+
484
+ # Export account
485
+ export_account_parser = account_subparsers.add_parser(
486
+ "export", help="Export an account to a file"
487
+ )
488
+ export_account_parser.add_argument(
489
+ "--name",
490
+ help="Account name to export (uses active account if not specified)",
491
+ )
492
+ export_account_parser.add_argument(
493
+ "--file",
494
+ dest="file_path",
495
+ help="File path to export to (default: <account_name>_hippius_account.json)",
496
+ )
497
+
498
+ # Import account
499
+ import_account_parser = account_subparsers.add_parser(
500
+ "import", help="Import an account from a file"
501
+ )
502
+ import_account_parser.add_argument(
503
+ "--file",
504
+ dest="file_path",
505
+ required=True,
506
+ help="File path to import from",
507
+ )
508
+ import_account_parser.add_argument(
509
+ "--encrypt",
510
+ action="store_true",
511
+ help="Encrypt the seed phrase during import",
512
+ )
513
+
514
+ # Account info
515
+ info_account_parser = account_subparsers.add_parser(
516
+ "info", help="Display detailed information about an account"
517
+ )
518
+ info_account_parser.add_argument(
519
+ "--name",
520
+ help="Account name to show info for (uses active account if not specified)",
521
+ )
522
+
523
+ # Account balance
524
+ balance_account_parser = account_subparsers.add_parser(
525
+ "balance", help="Check account balance"
526
+ )
527
+ balance_account_parser.add_argument(
528
+ "--name",
529
+ help="Account name to check balance for (uses active account if not specified)",
530
+ )
531
+ balance_account_parser.add_argument(
532
+ "--address",
533
+ help="Substrate address to check balance for (overrides account name)",
534
+ )
535
+
536
+ # Switch account
537
+ switch_account_parser = account_subparsers.add_parser(
538
+ "switch", help="Switch to a different account"
539
+ )
540
+ switch_account_parser.add_argument(
541
+ "account_name",
542
+ help="Account name to switch to",
543
+ )
544
+
545
+ # Delete account
546
+ delete_account_parser = account_subparsers.add_parser(
547
+ "delete", help="Delete an account"
548
+ )
549
+ delete_account_parser.add_argument(
550
+ "account_name",
551
+ help="Account name to delete",
552
+ )
553
+
554
+
555
+ def add_address_commands(subparsers):
556
+ """Add address management commands to the parser."""
557
+ # Address command
558
+ address_parser = subparsers.add_parser(
559
+ "address", help="Manage default address for read-only operations"
560
+ )
561
+ address_subparsers = address_parser.add_subparsers(
562
+ dest="address_action", help="Address action"
563
+ )
564
+
565
+ # Set default address
566
+ set_default_parser = address_subparsers.add_parser(
567
+ "set-default", help="Set the default address for read-only operations"
568
+ )
569
+ set_default_parser.add_argument(
570
+ "address",
571
+ help="Substrate account address to use as default",
572
+ )
573
+
574
+ # Get default address
575
+ address_subparsers.add_parser(
576
+ "get-default", help="Show the current default address for read-only operations"
577
+ )
578
+
579
+ # Clear default address
580
+ address_subparsers.add_parser(
581
+ "clear-default", help="Clear the default address for read-only operations"
582
+ )
583
+
584
+
585
+ def get_subparser(command: str) -> argparse.ArgumentParser:
586
+ """Get a subparser for a specific command.
587
+
588
+ Args:
589
+ command: The command name to get the subparser for
590
+
591
+ Returns:
592
+ The subparser for the specified command
593
+ """
594
+ parser = create_parser()
595
+ return parser._subparsers._group_actions[0].choices[command]
596
+
597
+
598
+ def parse_arguments() -> argparse.Namespace:
599
+ """Parse command line arguments."""
600
+ parser = create_parser()
601
+ args = parser.parse_args()
602
+ return args