pynukez 3.3.0__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.
Files changed (39) hide show
  1. pynukez-3.3.0/PKG-INFO +234 -0
  2. pynukez-3.3.0/README.md +188 -0
  3. pynukez-3.3.0/pynukez/__init__.py +1328 -0
  4. pynukez-3.3.0/pynukez/__main__.py +5 -0
  5. pynukez-3.3.0/pynukez/_async_client.py +2797 -0
  6. pynukez-3.3.0/pynukez/_async_http.py +147 -0
  7. pynukez-3.3.0/pynukez/_helpers.py +366 -0
  8. pynukez-3.3.0/pynukez/_http.py +520 -0
  9. pynukez-3.3.0/pynukez/auth.py +445 -0
  10. pynukez-3.3.0/pynukez/cli.py +89 -0
  11. pynukez-3.3.0/pynukez/client.py +3534 -0
  12. pynukez-3.3.0/pynukez/discovery.py +118 -0
  13. pynukez-3.3.0/pynukez/errors.py +518 -0
  14. pynukez-3.3.0/pynukez/evm_payment.py +593 -0
  15. pynukez-3.3.0/pynukez/hardening.py +292 -0
  16. pynukez-3.3.0/pynukez/payment.py +289 -0
  17. pynukez-3.3.0/pynukez/py.typed +2 -0
  18. pynukez-3.3.0/pynukez/signer.py +154 -0
  19. pynukez-3.3.0/pynukez/types.py +417 -0
  20. pynukez-3.3.0/pynukez.egg-info/PKG-INFO +234 -0
  21. pynukez-3.3.0/pynukez.egg-info/SOURCES.txt +37 -0
  22. pynukez-3.3.0/pynukez.egg-info/dependency_links.txt +1 -0
  23. pynukez-3.3.0/pynukez.egg-info/entry_points.txt +2 -0
  24. pynukez-3.3.0/pynukez.egg-info/requires.txt +24 -0
  25. pynukez-3.3.0/pynukez.egg-info/top_level.txt +1 -0
  26. pynukez-3.3.0/pyproject.toml +122 -0
  27. pynukez-3.3.0/setup.cfg +4 -0
  28. pynukez-3.3.0/tests/test_async_client.py +320 -0
  29. pynukez-3.3.0/tests/test_async_http_client.py +154 -0
  30. pynukez-3.3.0/tests/test_auth.py +447 -0
  31. pynukez-3.3.0/tests/test_client_methods.py +562 -0
  32. pynukez-3.3.0/tests/test_errors.py +89 -0
  33. pynukez-3.3.0/tests/test_evm_utils.py +33 -0
  34. pynukez-3.3.0/tests/test_hardening.py +52 -0
  35. pynukez-3.3.0/tests/test_http_client.py +230 -0
  36. pynukez-3.3.0/tests/test_operator_delegation.py +616 -0
  37. pynukez-3.3.0/tests/test_payment_utils.py +39 -0
  38. pynukez-3.3.0/tests/test_signer.py +164 -0
  39. pynukez-3.3.0/tests/test_types.py +150 -0
pynukez-3.3.0/PKG-INFO ADDED
@@ -0,0 +1,234 @@
1
+ Metadata-Version: 2.4
2
+ Name: pynukez
3
+ Version: 3.3.0
4
+ Summary: Nukez SDK — agent-native storage with cryptographic verification
5
+ Author-email: Nukez <dev@nukez.xyz>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/nukez/pynukez
8
+ Project-URL: Documentation, https://docs.nukez.xyz/sdk/python
9
+ Project-URL: Repository, https://github.com/nukez/pynukez
10
+ Project-URL: Issues, https://github.com/nukez/pynukez/issues
11
+ Keywords: ai,agent,autonomous,storage,solana,blockchain,cryptographic,verification,llm,tool-calling
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Requires-Python: >=3.9
25
+ Description-Content-Type: text/markdown
26
+ Requires-Dist: httpx>=0.24.0
27
+ Requires-Dist: pynacl>=1.5.0
28
+ Requires-Dist: base58>=2.1.0
29
+ Provides-Extra: solana
30
+ Requires-Dist: solana>=0.30.0; extra == "solana"
31
+ Requires-Dist: solders>=0.18.0; extra == "solana"
32
+ Provides-Extra: evm
33
+ Requires-Dist: web3>=6.0.0; extra == "evm"
34
+ Requires-Dist: eth-account>=0.10.0; extra == "evm"
35
+ Provides-Extra: dev
36
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
37
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
38
+ Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
39
+ Requires-Dist: black>=23.0.0; extra == "dev"
40
+ Requires-Dist: isort>=5.12.0; extra == "dev"
41
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
42
+ Requires-Dist: types-requests>=2.28.0; extra == "dev"
43
+ Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
44
+ Provides-Extra: all
45
+ Requires-Dist: pynukez[dev,evm,solana]; extra == "all"
46
+
47
+ # PyNukez
48
+
49
+ **Persistent storage for AI agents. Pay with SOL, store anything, get cryptographic proof.**
50
+
51
+ ```bash
52
+ pip install pynukez[solana]
53
+ ```
54
+
55
+ ## 30-Second Example
56
+
57
+ ```python
58
+ from pynukez import Nukez
59
+
60
+ client = Nukez(keypair_path="~/.config/solana/id.json")
61
+
62
+ # Buy storage
63
+ request = client.request_storage()
64
+ transfer = client.solana_transfer(request.pay_to_address, request.amount_sol)
65
+ receipt = client.confirm_storage(request.pay_req_id, transfer.signature)
66
+
67
+ # Use it
68
+ client.provision_locker(receipt.id)
69
+ urls = client.create_file(receipt.id, "notes.txt")
70
+ client.upload_bytes(urls.upload_url, b"Hello!")
71
+ data = client.download_bytes(urls.download_url) # b"Hello!"
72
+ ```
73
+
74
+ **That's it.** Your agent now has permanent storage with a cryptographic receipt.
75
+
76
+ ---
77
+
78
+ ## First Time? Start Here
79
+
80
+ ### 1. Get a Solana Wallet
81
+
82
+ ```bash
83
+ # Install Solana CLI
84
+ sh -c "$(curl -sSfL https://release.solana.com/stable/install)"
85
+
86
+ # Create wallet
87
+ solana-keygen new --outfile ~/.config/solana/id.json
88
+ ```
89
+
90
+ ### 2. Get Test Money (Free)
91
+
92
+ ```bash
93
+ solana config set --url devnet
94
+ solana airdrop 2
95
+ ```
96
+
97
+ ### 3. Install PyNukez
98
+
99
+ ```bash
100
+ pip install pynukez[solana]
101
+ ```
102
+
103
+ ### 4. Store Something
104
+
105
+ ```python
106
+ from pynukez import Nukez
107
+
108
+ client = Nukez(keypair_path="~/.config/solana/id.json")
109
+
110
+ # Buy storage (costs ~0.001 SOL on devnet)
111
+ request = client.request_storage()
112
+ transfer = client.solana_transfer(request.pay_to_address, request.amount_sol)
113
+ receipt = client.confirm_storage(request.pay_req_id, transfer.signature)
114
+
115
+ print(f"Your receipt: {receipt.id}") # Save this!
116
+
117
+ # Create your locker
118
+ client.provision_locker(receipt.id)
119
+
120
+ # Store a file
121
+ urls = client.create_file(receipt.id, "my_file.txt")
122
+ client.upload_bytes(urls.upload_url, b"My agent's data")
123
+
124
+ # Read it back
125
+ data = client.download_bytes(urls.download_url)
126
+ print(data) # b"My agent's data"
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Quick Reference
132
+
133
+ | What you want | Code |
134
+ |--------------|------|
135
+ | Buy storage | `request = client.request_storage()` |
136
+ | Pay | `transfer = client.solana_transfer(request.pay_to_address, request.amount_sol)` |
137
+ | Get receipt | `receipt = client.confirm_storage(request.pay_req_id, transfer.signature)` |
138
+ | Setup locker | `client.provision_locker(receipt.id)` |
139
+ | Store data | `urls = client.create_file(receipt.id, "file.txt")` then `client.upload_bytes(urls.upload_url, data)` |
140
+ | Get data | `data = client.download_bytes(urls.download_url)` |
141
+ | List files | `files = client.list_files(receipt.id)` |
142
+ | Delete file | `client.delete_file(receipt.id, "file.txt")` |
143
+ | Verify | `result = client.verify_storage(receipt.id)` |
144
+ | Merkle proof | `proof = client.get_merkle_proof(receipt.id, "file.txt")` |
145
+
146
+ ---
147
+
148
+ ## Sandboxed App Uploads
149
+
150
+ If your agent runs in a proxied app sandbox (for example, `/mnt/data` path restrictions), path uploads can fail even when locker auth is valid.
151
+
152
+ Use the sandbox ingest flow instead:
153
+
154
+ ```python
155
+ job = client.sandbox_create_ingest_job(
156
+ receipt_id=receipt.id,
157
+ files=[{"filename": "image.png", "content_type": "image/png"}],
158
+ )
159
+
160
+ client.sandbox_append_ingest_part(
161
+ receipt_id=receipt.id,
162
+ job_id=job["job_id"],
163
+ file_id=job["files"][0]["file_id"],
164
+ part_no=0,
165
+ payload_b64="<chunk-0-base64>",
166
+ is_last=True,
167
+ )
168
+
169
+ result = client.sandbox_complete_ingest_job(
170
+ receipt_id=receipt.id,
171
+ job_id=job["job_id"],
172
+ )
173
+ ```
174
+
175
+ Convenience helpers are available:
176
+ - `client.sandbox_upload_bytes(...)`
177
+ - `client.sandbox_upload_base64(...)`
178
+ - `client.sandbox_upload_file_path(...)`
179
+
180
+ Important: if a valid `receipt_id` already exists, reuse it. Do not purchase storage again unless explicitly requested.
181
+
182
+ ---
183
+
184
+ ## Important
185
+
186
+ **Save your `receipt.id`** — you need it for everything.
187
+
188
+ ```python
189
+ # First time
190
+ receipt = client.confirm_storage(...)
191
+ print(receipt.id) # Save this string somewhere!
192
+
193
+ # Later
194
+ files = client.list_files("your_saved_receipt_id")
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Going to Production
200
+
201
+ Change one line:
202
+
203
+ ```python
204
+ # Devnet (testing)
205
+ client = Nukez(keypair_path="~/.config/solana/id.json", network="devnet")
206
+
207
+ # Mainnet (production)
208
+ client = Nukez(keypair_path="~/.config/solana/id.json", network="mainnet-beta")
209
+ ```
210
+
211
+ ---
212
+
213
+ ## Common Issues
214
+
215
+ | Problem | Fix |
216
+ |---------|-----|
217
+ | "Transaction not found" | Wait 3 seconds and retry `confirm_storage()` |
218
+ | "Insufficient funds" | Run `solana airdrop 2` (devnet only) |
219
+ | "URL expired" | Call `client.get_file_urls(receipt_id, filename)` for fresh URLs |
220
+ | "File not found" | Check `client.list_files(receipt_id)` to see what exists |
221
+
222
+ ---
223
+
224
+ ## Links
225
+
226
+ - [Examples](./examples/) — Working code you can copy
227
+ - [API Reference](./docs/API.md) — Every method explained
228
+ - [Source Code](./pynukez/) — Read it yourself
229
+
230
+ ---
231
+
232
+ ## License
233
+
234
+ MIT
@@ -0,0 +1,188 @@
1
+ # PyNukez
2
+
3
+ **Persistent storage for AI agents. Pay with SOL, store anything, get cryptographic proof.**
4
+
5
+ ```bash
6
+ pip install pynukez[solana]
7
+ ```
8
+
9
+ ## 30-Second Example
10
+
11
+ ```python
12
+ from pynukez import Nukez
13
+
14
+ client = Nukez(keypair_path="~/.config/solana/id.json")
15
+
16
+ # Buy storage
17
+ request = client.request_storage()
18
+ transfer = client.solana_transfer(request.pay_to_address, request.amount_sol)
19
+ receipt = client.confirm_storage(request.pay_req_id, transfer.signature)
20
+
21
+ # Use it
22
+ client.provision_locker(receipt.id)
23
+ urls = client.create_file(receipt.id, "notes.txt")
24
+ client.upload_bytes(urls.upload_url, b"Hello!")
25
+ data = client.download_bytes(urls.download_url) # b"Hello!"
26
+ ```
27
+
28
+ **That's it.** Your agent now has permanent storage with a cryptographic receipt.
29
+
30
+ ---
31
+
32
+ ## First Time? Start Here
33
+
34
+ ### 1. Get a Solana Wallet
35
+
36
+ ```bash
37
+ # Install Solana CLI
38
+ sh -c "$(curl -sSfL https://release.solana.com/stable/install)"
39
+
40
+ # Create wallet
41
+ solana-keygen new --outfile ~/.config/solana/id.json
42
+ ```
43
+
44
+ ### 2. Get Test Money (Free)
45
+
46
+ ```bash
47
+ solana config set --url devnet
48
+ solana airdrop 2
49
+ ```
50
+
51
+ ### 3. Install PyNukez
52
+
53
+ ```bash
54
+ pip install pynukez[solana]
55
+ ```
56
+
57
+ ### 4. Store Something
58
+
59
+ ```python
60
+ from pynukez import Nukez
61
+
62
+ client = Nukez(keypair_path="~/.config/solana/id.json")
63
+
64
+ # Buy storage (costs ~0.001 SOL on devnet)
65
+ request = client.request_storage()
66
+ transfer = client.solana_transfer(request.pay_to_address, request.amount_sol)
67
+ receipt = client.confirm_storage(request.pay_req_id, transfer.signature)
68
+
69
+ print(f"Your receipt: {receipt.id}") # Save this!
70
+
71
+ # Create your locker
72
+ client.provision_locker(receipt.id)
73
+
74
+ # Store a file
75
+ urls = client.create_file(receipt.id, "my_file.txt")
76
+ client.upload_bytes(urls.upload_url, b"My agent's data")
77
+
78
+ # Read it back
79
+ data = client.download_bytes(urls.download_url)
80
+ print(data) # b"My agent's data"
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Quick Reference
86
+
87
+ | What you want | Code |
88
+ |--------------|------|
89
+ | Buy storage | `request = client.request_storage()` |
90
+ | Pay | `transfer = client.solana_transfer(request.pay_to_address, request.amount_sol)` |
91
+ | Get receipt | `receipt = client.confirm_storage(request.pay_req_id, transfer.signature)` |
92
+ | Setup locker | `client.provision_locker(receipt.id)` |
93
+ | Store data | `urls = client.create_file(receipt.id, "file.txt")` then `client.upload_bytes(urls.upload_url, data)` |
94
+ | Get data | `data = client.download_bytes(urls.download_url)` |
95
+ | List files | `files = client.list_files(receipt.id)` |
96
+ | Delete file | `client.delete_file(receipt.id, "file.txt")` |
97
+ | Verify | `result = client.verify_storage(receipt.id)` |
98
+ | Merkle proof | `proof = client.get_merkle_proof(receipt.id, "file.txt")` |
99
+
100
+ ---
101
+
102
+ ## Sandboxed App Uploads
103
+
104
+ If your agent runs in a proxied app sandbox (for example, `/mnt/data` path restrictions), path uploads can fail even when locker auth is valid.
105
+
106
+ Use the sandbox ingest flow instead:
107
+
108
+ ```python
109
+ job = client.sandbox_create_ingest_job(
110
+ receipt_id=receipt.id,
111
+ files=[{"filename": "image.png", "content_type": "image/png"}],
112
+ )
113
+
114
+ client.sandbox_append_ingest_part(
115
+ receipt_id=receipt.id,
116
+ job_id=job["job_id"],
117
+ file_id=job["files"][0]["file_id"],
118
+ part_no=0,
119
+ payload_b64="<chunk-0-base64>",
120
+ is_last=True,
121
+ )
122
+
123
+ result = client.sandbox_complete_ingest_job(
124
+ receipt_id=receipt.id,
125
+ job_id=job["job_id"],
126
+ )
127
+ ```
128
+
129
+ Convenience helpers are available:
130
+ - `client.sandbox_upload_bytes(...)`
131
+ - `client.sandbox_upload_base64(...)`
132
+ - `client.sandbox_upload_file_path(...)`
133
+
134
+ Important: if a valid `receipt_id` already exists, reuse it. Do not purchase storage again unless explicitly requested.
135
+
136
+ ---
137
+
138
+ ## Important
139
+
140
+ **Save your `receipt.id`** — you need it for everything.
141
+
142
+ ```python
143
+ # First time
144
+ receipt = client.confirm_storage(...)
145
+ print(receipt.id) # Save this string somewhere!
146
+
147
+ # Later
148
+ files = client.list_files("your_saved_receipt_id")
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Going to Production
154
+
155
+ Change one line:
156
+
157
+ ```python
158
+ # Devnet (testing)
159
+ client = Nukez(keypair_path="~/.config/solana/id.json", network="devnet")
160
+
161
+ # Mainnet (production)
162
+ client = Nukez(keypair_path="~/.config/solana/id.json", network="mainnet-beta")
163
+ ```
164
+
165
+ ---
166
+
167
+ ## Common Issues
168
+
169
+ | Problem | Fix |
170
+ |---------|-----|
171
+ | "Transaction not found" | Wait 3 seconds and retry `confirm_storage()` |
172
+ | "Insufficient funds" | Run `solana airdrop 2` (devnet only) |
173
+ | "URL expired" | Call `client.get_file_urls(receipt_id, filename)` for fresh URLs |
174
+ | "File not found" | Check `client.list_files(receipt_id)` to see what exists |
175
+
176
+ ---
177
+
178
+ ## Links
179
+
180
+ - [Examples](./examples/) — Working code you can copy
181
+ - [API Reference](./docs/API.md) — Every method explained
182
+ - [Source Code](./pynukez/) — Read it yourself
183
+
184
+ ---
185
+
186
+ ## License
187
+
188
+ MIT