hippius 0.2.3__tar.gz → 0.2.4__tar.gz
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.
- {hippius-0.2.3 → hippius-0.2.4}/PKG-INFO +207 -151
- {hippius-0.2.3 → hippius-0.2.4}/README.md +209 -152
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/__init__.py +10 -21
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/cli.py +7 -1
- hippius-0.2.4/hippius_sdk/cli_assets.py +10 -0
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/cli_handlers.py +540 -137
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/cli_parser.py +5 -0
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/cli_rich.py +2 -8
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/client.py +14 -14
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/config.py +108 -141
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/ipfs.py +64 -43
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/substrate.py +24 -33
- {hippius-0.2.3 → hippius-0.2.4}/pyproject.toml +1 -1
- hippius-0.2.3/hippius_sdk/cli_assets.py +0 -8
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/ipfs_core.py +0 -0
- {hippius-0.2.3 → hippius-0.2.4}/hippius_sdk/utils.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: hippius
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.4
|
4
4
|
Summary: Python SDK and CLI for Hippius blockchain storage
|
5
5
|
Home-page: https://github.com/thenervelab/hippius-sdk
|
6
6
|
Author: Dubs
|
@@ -44,6 +44,7 @@ A Python SDK and CLI for interacting with Hippius blockchain storage, designed s
|
|
44
44
|
- Substrate blockchain integration for decentralized storage references
|
45
45
|
- End-to-end encryption for secure file storage and retrieval
|
46
46
|
- Built-in CLI tools for encryption key generation
|
47
|
+
- Asynchronous API for efficient I/O operations
|
47
48
|
|
48
49
|
## Installation
|
49
50
|
|
@@ -61,6 +62,7 @@ poetry add hippius -E clipboard
|
|
61
62
|
## Quick Start
|
62
63
|
|
63
64
|
```python
|
65
|
+
import asyncio
|
64
66
|
from hippius_sdk import HippiusClient
|
65
67
|
|
66
68
|
# Initialize the client with default connections to Hippius network
|
@@ -72,41 +74,46 @@ client = HippiusClient(
|
|
72
74
|
ipfs_api_url="https://store.hippius.network", # For uploads (default)
|
73
75
|
)
|
74
76
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
print(f"File
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
print(f"
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
print(f"
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
print(f"
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
print(f"
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
77
|
+
async def main():
|
78
|
+
# Upload a file to IPFS
|
79
|
+
result = await client.upload_file("path/to/your/model.pt")
|
80
|
+
print(f"File uploaded with CID: {result['cid']}")
|
81
|
+
print(f"File size: {result['size_formatted']}")
|
82
|
+
|
83
|
+
# Download a file from IPFS
|
84
|
+
dl_result = await client.download_file(result['cid'], "path/to/save/model.pt")
|
85
|
+
print(f"Download successful in {dl_result['elapsed_seconds']} seconds")
|
86
|
+
print(f"File size: {dl_result['size_formatted']}")
|
87
|
+
|
88
|
+
# Check if a file exists
|
89
|
+
exists_result = await client.exists(result['cid'])
|
90
|
+
print(f"File exists: {exists_result['exists']}")
|
91
|
+
print(f"Gateway URL: {exists_result['gateway_url']}")
|
92
|
+
|
93
|
+
# Get file content directly
|
94
|
+
content_result = await client.cat(result['cid'])
|
95
|
+
if content_result['is_text']:
|
96
|
+
print(f"Content preview: {content_result['text_preview']}")
|
97
|
+
else:
|
98
|
+
print(f"Binary content (hex): {content_result['hex_preview']}")
|
99
|
+
print(f"Content size: {content_result['size_formatted']}")
|
100
|
+
|
101
|
+
# Pin a file to ensure it stays on the network
|
102
|
+
pin_result = await client.pin(result['cid'])
|
103
|
+
print(f"Pinning successful: {pin_result['success']}")
|
104
|
+
print(f"Message: {pin_result['message']}")
|
105
|
+
|
106
|
+
# Format a CID for display (non-async utility function)
|
107
|
+
formatted_cid = client.format_cid(result['cid'])
|
108
|
+
print(f"Formatted CID: {formatted_cid}")
|
109
|
+
|
110
|
+
# Format file size for display (non-async utility function)
|
111
|
+
formatted_size = client.format_size(1024 * 1024)
|
112
|
+
print(f"Formatted size: {formatted_size}") # Output: 1.00 MB
|
113
|
+
|
114
|
+
# Run the async function
|
115
|
+
if __name__ == "__main__":
|
116
|
+
asyncio.run(main())
|
110
117
|
```
|
111
118
|
|
112
119
|
## Encryption Support
|
@@ -137,6 +144,7 @@ The SDK can be configured to use encryption in several ways:
|
|
137
144
|
2. Directly in code:
|
138
145
|
```python
|
139
146
|
import base64
|
147
|
+
import asyncio
|
140
148
|
from hippius_sdk import HippiusClient
|
141
149
|
|
142
150
|
# Decode the base64 key
|
@@ -148,9 +156,13 @@ The SDK can be configured to use encryption in several ways:
|
|
148
156
|
encryption_key=encryption_key
|
149
157
|
)
|
150
158
|
|
151
|
-
|
152
|
-
|
153
|
-
|
159
|
+
async def main():
|
160
|
+
# Generate a new key programmatically (non-async utility method)
|
161
|
+
encoded_key = client.generate_encryption_key()
|
162
|
+
print(f"Generated key: {encoded_key}")
|
163
|
+
|
164
|
+
# Run the async function
|
165
|
+
asyncio.run(main())
|
154
166
|
```
|
155
167
|
|
156
168
|
### Using Encryption
|
@@ -158,22 +170,31 @@ The SDK can be configured to use encryption in several ways:
|
|
158
170
|
Once configured, encryption works transparently:
|
159
171
|
|
160
172
|
```python
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
# Explicitly enable/disable encryption for a specific operation
|
165
|
-
encrypted_result = client.upload_file("sensitive_data.txt", encrypt=True)
|
166
|
-
unencrypted_result = client.upload_file("public_data.txt", encrypt=False)
|
167
|
-
|
168
|
-
# Download and decrypt automatically
|
169
|
-
dl_result = client.download_file(encrypted_result['cid'], "decrypted_file.txt")
|
173
|
+
import asyncio
|
174
|
+
from hippius_sdk import HippiusClient
|
170
175
|
|
171
|
-
|
172
|
-
decrypted_result = client.download_file(encrypted_result['cid'], "output.txt", decrypt=True)
|
173
|
-
raw_result = client.download_file(encrypted_result['cid'], "still_encrypted.txt", decrypt=False)
|
176
|
+
client = HippiusClient()
|
174
177
|
|
175
|
-
|
176
|
-
|
178
|
+
async def main():
|
179
|
+
# Upload with encryption (uses default setting)
|
180
|
+
result = await client.upload_file("sensitive_data.txt")
|
181
|
+
|
182
|
+
# Explicitly enable/disable encryption for a specific operation
|
183
|
+
encrypted_result = await client.upload_file("sensitive_data.txt", encrypt=True)
|
184
|
+
unencrypted_result = await client.upload_file("public_data.txt", encrypt=False)
|
185
|
+
|
186
|
+
# Download and decrypt automatically
|
187
|
+
dl_result = await client.download_file(encrypted_result['cid'], "decrypted_file.txt")
|
188
|
+
|
189
|
+
# Explicitly control decryption
|
190
|
+
decrypted_result = await client.download_file(encrypted_result['cid'], "output.txt", decrypt=True)
|
191
|
+
raw_result = await client.download_file(encrypted_result['cid'], "still_encrypted.txt", decrypt=False)
|
192
|
+
|
193
|
+
# View encrypted content
|
194
|
+
content = await client.cat(encrypted_result['cid'], decrypt=True)
|
195
|
+
|
196
|
+
# Run the async function
|
197
|
+
asyncio.run(main())
|
177
198
|
```
|
178
199
|
|
179
200
|
## Erasure Coding
|
@@ -190,37 +211,42 @@ Hippius SDK supports Reed-Solomon erasure coding for reliable and resilient file
|
|
190
211
|
### Using Erasure Coding
|
191
212
|
|
192
213
|
```python
|
214
|
+
import asyncio
|
193
215
|
from hippius_sdk import HippiusClient
|
194
216
|
|
195
217
|
client = HippiusClient()
|
196
218
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
219
|
+
async def main():
|
220
|
+
# Erasure code a file with default parameters (k=3, m=5)
|
221
|
+
result = await client.erasure_code_file("large_file.mp4")
|
222
|
+
metadata_cid = result["metadata_cid"]
|
223
|
+
|
224
|
+
# Use custom parameters for more redundancy
|
225
|
+
result = await client.erasure_code_file(
|
226
|
+
file_path="important_data.zip",
|
227
|
+
k=4, # Need 4 chunks to reconstruct
|
228
|
+
m=10, # Create 10 chunks total (6 redundant)
|
229
|
+
chunk_size=2097152, # 2MB chunks
|
230
|
+
encrypt=True # Encrypt before splitting
|
231
|
+
)
|
232
|
+
|
233
|
+
# Store erasure-coded file in Hippius marketplace
|
234
|
+
result = await client.store_erasure_coded_file(
|
235
|
+
file_path="critical_backup.tar",
|
236
|
+
k=3,
|
237
|
+
m=5,
|
238
|
+
encrypt=True,
|
239
|
+
miner_ids=["miner1", "miner2", "miner3"]
|
240
|
+
)
|
241
|
+
|
242
|
+
# Reconstruct a file from its metadata
|
243
|
+
reconstructed_path = await client.reconstruct_from_erasure_code(
|
244
|
+
metadata_cid=metadata_cid,
|
245
|
+
output_file="reconstructed_file.mp4"
|
246
|
+
)
|
247
|
+
|
248
|
+
# Run the async function
|
249
|
+
asyncio.run(main())
|
224
250
|
```
|
225
251
|
|
226
252
|
### When to Use Erasure Coding
|
@@ -535,55 +561,60 @@ HIPPIUS_ENCRYPT_BY_DEFAULT=true|false
|
|
535
561
|
### IPFS Operations
|
536
562
|
|
537
563
|
```python
|
564
|
+
import asyncio
|
538
565
|
from hippius_sdk import IPFSClient
|
539
566
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
567
|
+
async def main():
|
568
|
+
# Initialize the IPFS client (uses Hippius relay node by default)
|
569
|
+
ipfs_client = IPFSClient()
|
570
|
+
|
571
|
+
# Or specify custom endpoints
|
572
|
+
ipfs_client = IPFSClient(
|
573
|
+
gateway="https://get.hippius.network", # For downloads
|
574
|
+
api_url="http://relay-fr.hippius.network:5001" # For uploads
|
575
|
+
)
|
576
|
+
|
577
|
+
# Upload a file
|
578
|
+
result = await ipfs_client.upload_file("path/to/your/file.txt")
|
579
|
+
cid = result["cid"]
|
580
|
+
size = result["size_formatted"]
|
581
|
+
|
582
|
+
# Upload a directory
|
583
|
+
dir_result = await ipfs_client.upload_directory("path/to/your/directory")
|
584
|
+
dir_cid = dir_result["cid"]
|
585
|
+
file_count = dir_result["file_count"]
|
586
|
+
total_size = dir_result["size_formatted"]
|
587
|
+
|
588
|
+
# Download a file
|
589
|
+
dl_result = await ipfs_client.download_file(cid, "path/to/save/file.txt")
|
590
|
+
success = dl_result["success"]
|
591
|
+
elapsed_time = dl_result["elapsed_seconds"]
|
592
|
+
|
593
|
+
# Check if a CID exists
|
594
|
+
exists_result = await ipfs_client.exists(cid)
|
595
|
+
exists = exists_result["exists"]
|
596
|
+
gateway_url = exists_result["gateway_url"]
|
597
|
+
|
598
|
+
# Get file content directly
|
599
|
+
content_result = await ipfs_client.cat(cid)
|
600
|
+
content = content_result["content"]
|
601
|
+
is_text = content_result["is_text"]
|
602
|
+
preview = content_result["text_preview"] if is_text else content_result["hex_preview"]
|
603
|
+
|
604
|
+
# Pin a file
|
605
|
+
pin_result = await ipfs_client.pin(cid)
|
606
|
+
success = pin_result["success"]
|
607
|
+
message = pin_result["message"]
|
608
|
+
|
609
|
+
# Format a CID (non-async utility function)
|
610
|
+
formatted_cid = ipfs_client.format_cid("6261666b7265696134...") # Hex-encoded CID
|
611
|
+
# Will return a proper formatted CID like "bafkrei..."
|
612
|
+
|
613
|
+
# Format a file size (non-async utility function)
|
614
|
+
human_readable = ipfs_client.format_size(1048576) # 1 MB
|
615
|
+
|
616
|
+
# Run the async function
|
617
|
+
asyncio.run(main())
|
587
618
|
```
|
588
619
|
|
589
620
|
### IPFS Connection Methods
|
@@ -665,6 +696,7 @@ hippius config import-env
|
|
665
696
|
### Using Configuration in Code
|
666
697
|
|
667
698
|
```python
|
699
|
+
import asyncio
|
668
700
|
from hippius_sdk import get_config_value, set_config_value, HippiusClient
|
669
701
|
|
670
702
|
# Get a configuration value
|
@@ -676,6 +708,13 @@ set_config_value("ipfs", "gateway", "https://dweb.link")
|
|
676
708
|
|
677
709
|
# Client will automatically use configuration values
|
678
710
|
client = HippiusClient()
|
711
|
+
|
712
|
+
async def main():
|
713
|
+
# Your async code here
|
714
|
+
pass
|
715
|
+
|
716
|
+
# Run the async function
|
717
|
+
asyncio.run(main())
|
679
718
|
```
|
680
719
|
|
681
720
|
## Development
|
@@ -744,6 +783,7 @@ To test the SDK components, you can create a small test script:
|
|
744
783
|
|
745
784
|
```python
|
746
785
|
# test_script.py
|
786
|
+
import asyncio
|
747
787
|
from hippius_sdk import HippiusClient
|
748
788
|
from dotenv import load_dotenv
|
749
789
|
import os
|
@@ -754,13 +794,17 @@ load_dotenv()
|
|
754
794
|
# Create a client
|
755
795
|
client = HippiusClient()
|
756
796
|
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
797
|
+
async def test_ipfs_client():
|
798
|
+
# Test a simple operation
|
799
|
+
print("Testing IPFS client...")
|
800
|
+
try:
|
801
|
+
result = await client.exists("QmZ4tDuvesekSs4qM5ZBKpXiZGun7S2CYtEZRB3DYXkjGx")
|
802
|
+
print(f"Result: {result}")
|
803
|
+
except Exception as e:
|
804
|
+
print(f"Error: {e}")
|
805
|
+
|
806
|
+
# Run the async function
|
807
|
+
asyncio.run(test_ipfs_client())
|
764
808
|
```
|
765
809
|
|
766
810
|
Then run it:
|
@@ -879,6 +923,7 @@ This provides enhanced security by:
|
|
879
923
|
When interacting with the Hippius SDK programmatically, you can provide the password when initializing clients:
|
880
924
|
|
881
925
|
```python
|
926
|
+
import asyncio
|
882
927
|
from hippius_sdk import HippiusClient
|
883
928
|
|
884
929
|
# The client will prompt for password when needed to decrypt the seed phrase
|
@@ -886,6 +931,13 @@ client = HippiusClient()
|
|
886
931
|
|
887
932
|
# Or you can provide a password when initializing
|
888
933
|
client = HippiusClient(seed_phrase_password="your-password")
|
934
|
+
|
935
|
+
async def main():
|
936
|
+
# Your async code here
|
937
|
+
pass
|
938
|
+
|
939
|
+
# Run the async function
|
940
|
+
asyncio.run(main())
|
889
941
|
```
|
890
942
|
|
891
943
|
### Multi-Account Management
|
@@ -923,25 +975,29 @@ Key features of the multi-account system:
|
|
923
975
|
To use multiple accounts in your code:
|
924
976
|
|
925
977
|
```python
|
978
|
+
import asyncio
|
926
979
|
from hippius_sdk import HippiusClient, set_active_account, list_accounts
|
927
980
|
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
client
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
981
|
+
async def main():
|
982
|
+
# List all accounts
|
983
|
+
accounts = list_accounts()
|
984
|
+
for name, data in accounts.items():
|
985
|
+
print(f"{name}: {data.get('ss58_address')}")
|
986
|
+
|
987
|
+
# Switch the active account
|
988
|
+
set_active_account("my-validator")
|
989
|
+
|
990
|
+
# Create a client with the active account
|
991
|
+
client = HippiusClient(seed_phrase_password="your-password")
|
992
|
+
|
993
|
+
# Or specify a different account to use
|
994
|
+
client = HippiusClient(
|
995
|
+
account_name="my-developer-account",
|
996
|
+
seed_phrase_password="your-password"
|
997
|
+
)
|
998
|
+
|
999
|
+
# Run the async function
|
1000
|
+
asyncio.run(main())
|
944
1001
|
```
|
945
1002
|
|
946
1003
|
The multi-account system makes it easier to manage multiple identities while maintaining security and convenience.
|
947
|
-
|