pinarkive-sdk 2.0.0__tar.gz → 2.1.45__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.
@@ -0,0 +1,455 @@
1
+ Metadata-Version: 2.4
2
+ Name: pinarkive-sdk
3
+ Version: 2.1.45
4
+ Summary: Python SDK for the Pinarkive API v2.1 - Easy IPFS file management with directory DAG uploads, file renaming, and enhanced API key management. Includes type hints for better IDE support.
5
+ Author: ITCS VIP, Joel_da
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/pinarkive/pinarkive-sdk
8
+ Project-URL: Repository, https://github.com/pinarkive/pinarkive-sdk.git
9
+ Requires-Python: >=3.7
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: requests>=2.31.0
12
+
13
+ # Pinarkive Python SDK
14
+
15
+ Python client for the Pinarkive API v2.1. Easy IPFS file management with directory DAG uploads, file renaming, and enhanced API key management. Includes type hints for better IDE support and Pythonic usage patterns.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install pinarkive-sdk
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```python
26
+ from pinarkive_client import PinarkiveClient
27
+
28
+ # Initialize with API key
29
+ client = PinarkiveClient(api_key="your-api-key-here")
30
+
31
+ # Upload a file
32
+ result = client.upload_file("document.pdf")
33
+ print(f"File uploaded: {result.json()['cid']}")
34
+
35
+ # Generate API key
36
+ token = client.generate_token("my-app", {
37
+ "expires_in_days": 30
38
+ })
39
+ print(f"New API key: {token.json()['token']}")
40
+ ```
41
+
42
+ ## Authentication
43
+
44
+ The SDK supports two authentication methods:
45
+
46
+ ### API Key Authentication (Recommended)
47
+ ```python
48
+ client = PinarkiveClient(api_key="your-api-key-here")
49
+ ```
50
+
51
+ ### JWT Token Authentication
52
+ ```python
53
+ client = PinarkiveClient(token="your-jwt-token-here")
54
+ ```
55
+
56
+ ## Basic Usage
57
+
58
+ ### File Upload
59
+ ```python
60
+ # Upload single file
61
+ result = client.upload_file("document.pdf")
62
+ response_data = result.json()
63
+ print(f"CID: {response_data['cid']}")
64
+ print(f"Status: {response_data['status']}")
65
+ ```
66
+
67
+ ### Directory Upload
68
+ ```python
69
+ # Upload directory from local path
70
+ result = client.upload_directory("/path/to/directory")
71
+ print(f"Directory CID: {result.json()['cid']}")
72
+ ```
73
+
74
+ ### List Uploads
75
+ ```python
76
+ # List all uploaded files with pagination
77
+ result = client.list_uploads(page=1, limit=20)
78
+ response_data = result.json()
79
+ print(f"Uploads: {response_data['uploads']}")
80
+ print(f"Total: {response_data['pagination']['total']}")
81
+ ```
82
+
83
+ ## Advanced Features
84
+
85
+ ### Directory DAG Upload
86
+ Upload entire directory structures as DAG (Directed Acyclic Graph):
87
+
88
+ ```python
89
+ # Create project structure
90
+ project_files = {
91
+ "src/index.py": "print('Hello World')",
92
+ "src/utils.py": "def utils(): pass",
93
+ "requirements.txt": "requests>=2.31.0",
94
+ "README.md": "# My Project\n\nThis is my project."
95
+ }
96
+
97
+ # Upload as DAG
98
+ result = client.upload_directory_dag(project_files, dir_name="my-project")
99
+ response_data = result.json()
100
+ print(f"DAG CID: {response_data['dagCid']}")
101
+ print(f"Files: {response_data['files']}")
102
+ ```
103
+
104
+ ### Directory Cluster Upload
105
+ ```python
106
+ # Upload using cluster-based approach
107
+ files = [
108
+ {"path": "file1.txt", "content": "Content 1"},
109
+ {"path": "file2.txt", "content": "Content 2"}
110
+ ]
111
+
112
+ result = client.upload_directory_cluster(files)
113
+ print(f"Cluster CID: {result.json()['cid']}")
114
+ ```
115
+
116
+ ### Upload File to Existing Directory
117
+ ```python
118
+ # Add file to existing directory
119
+ result = client.upload_file_to_directory("new-file.txt", "existing-directory-path")
120
+ print(f"File added to directory: {result.json()['cid']}")
121
+ ```
122
+
123
+ ### File Renaming
124
+ ```python
125
+ # Rename an uploaded file
126
+ result = client.rename_file("upload-id-here", "new-file-name.pdf")
127
+ print(f"File renamed: {result.json()['updated']}")
128
+ ```
129
+
130
+ ### Pinning Operations
131
+
132
+ #### Basic CID Pinning
133
+ ```python
134
+ result = client.pin_cid("QmYourCIDHere")
135
+ print(f"CID pinned: {result.json()['pinned']}")
136
+ ```
137
+
138
+ #### Pin with Custom Name
139
+ ```python
140
+ result = client.pin_cid_with_name("QmYourCIDHere", "my-important-file")
141
+ print(f"CID pinned with name: {result.json()['pinned']}")
142
+ ```
143
+
144
+ ### API Key Management
145
+
146
+ #### Generate API Key
147
+ ```python
148
+ # Basic token generation
149
+ token = client.generate_token("my-app")
150
+
151
+ # Advanced token with options
152
+ token = client.generate_token("my-app", {
153
+ "expires_in_days": 30,
154
+ "ip_allowlist": ["192.168.1.1", "10.0.0.1"],
155
+ "permissions": ["upload", "pin"]
156
+ })
157
+ print(f"New API key: {token.json()['token']}")
158
+ ```
159
+
160
+ #### List API Keys
161
+ ```python
162
+ tokens = client.list_tokens()
163
+ print(f"API Keys: {tokens.json()['tokens']}")
164
+ ```
165
+
166
+ #### Revoke API Key
167
+ ```python
168
+ result = client.revoke_token("my-app")
169
+ print(f"Token revoked: {result.json()['revoked']}")
170
+ ```
171
+
172
+ ## Type Hints Support
173
+
174
+ The SDK includes comprehensive type hints for better IDE support:
175
+
176
+ ```python
177
+ from typing import Dict, Any, Optional
178
+ from pinarkive_client import PinarkiveClient
179
+
180
+ # Type hints provide better autocomplete and error checking
181
+ client = PinarkiveClient(api_key="your-key")
182
+
183
+ # IDE will show parameter types and return types
184
+ def upload_project_files(files: Dict[str, str]) -> Any:
185
+ return client.upload_directory_dag(files, dir_name="project")
186
+
187
+ # Type hints for options
188
+ token_options: Dict[str, Any] = {
189
+ "expires_in_days": 30,
190
+ "ip_allowlist": ["192.168.1.1"]
191
+ }
192
+ token = client.generate_token("my-app", token_options)
193
+ ```
194
+
195
+ ## Error Handling
196
+
197
+ ```python
198
+ import requests
199
+
200
+ try:
201
+ result = client.upload_file("document.pdf")
202
+ print("Success:", result.json())
203
+ except requests.exceptions.RequestException as e:
204
+ if hasattr(e, 'response') and e.response is not None:
205
+ print(f"API Error: {e.response.status_code}")
206
+ print(f"Response: {e.response.json()}")
207
+ else:
208
+ print(f"Network Error: {e}")
209
+ ```
210
+
211
+ ## Integration Examples
212
+
213
+ ### Django Integration
214
+ ```python
215
+ # views.py
216
+ from django.http import JsonResponse
217
+ from django.views.decorators.csrf import csrf_exempt
218
+ from pinarkive_client import PinarkiveClient
219
+ import json
220
+
221
+ @csrf_exempt
222
+ def upload_file(request):
223
+ if request.method == 'POST':
224
+ client = PinarkiveClient(api_key=settings.PINARKIVE_API_KEY)
225
+
226
+ uploaded_file = request.FILES['file']
227
+ # Save temporarily
228
+ with open(f'/tmp/{uploaded_file.name}', 'wb+') as destination:
229
+ for chunk in uploaded_file.chunks():
230
+ destination.write(chunk)
231
+
232
+ try:
233
+ result = client.upload_file(f'/tmp/{uploaded_file.name}')
234
+ return JsonResponse(result.json())
235
+ except Exception as e:
236
+ return JsonResponse({'error': str(e)}, status=500)
237
+
238
+ return JsonResponse({'error': 'Method not allowed'}, status=405)
239
+ ```
240
+
241
+ ### Flask Integration
242
+ ```python
243
+ from flask import Flask, request, jsonify
244
+ from pinarkive_client import PinarkiveClient
245
+ import os
246
+
247
+ app = Flask(__name__)
248
+ client = PinarkiveClient(api_key=os.environ.get('PINARKIVE_API_KEY'))
249
+
250
+ @app.route('/upload', methods=['POST'])
251
+ def upload_file():
252
+ if 'file' not in request.files:
253
+ return jsonify({'error': 'No file provided'}), 400
254
+
255
+ file = request.files['file']
256
+ if file.filename == '':
257
+ return jsonify({'error': 'No file selected'}), 400
258
+
259
+ # Save temporarily
260
+ temp_path = f'/tmp/{file.filename}'
261
+ file.save(temp_path)
262
+
263
+ try:
264
+ result = client.upload_file(temp_path)
265
+ os.remove(temp_path) # Clean up
266
+ return jsonify(result.json())
267
+ except Exception as e:
268
+ os.remove(temp_path) # Clean up on error
269
+ return jsonify({'error': str(e)}), 500
270
+
271
+ @app.route('/files', methods=['GET'])
272
+ def list_files():
273
+ try:
274
+ result = client.list_uploads()
275
+ return jsonify(result.json())
276
+ except Exception as e:
277
+ return jsonify({'error': str(e)}), 500
278
+ ```
279
+
280
+ ### FastAPI Integration
281
+ ```python
282
+ from fastapi import FastAPI, File, UploadFile, HTTPException
283
+ from pinarkive_client import PinarkiveClient
284
+ import tempfile
285
+ import os
286
+
287
+ app = FastAPI()
288
+ client = PinarkiveClient(api_key=os.environ.get('PINARKIVE_API_KEY'))
289
+
290
+ @app.post("/upload")
291
+ async def upload_file(file: UploadFile = File(...)):
292
+ # Create temporary file
293
+ with tempfile.NamedTemporaryFile(delete=False) as temp_file:
294
+ content = await file.read()
295
+ temp_file.write(content)
296
+ temp_file.flush()
297
+
298
+ try:
299
+ result = client.upload_file(temp_file.name)
300
+ os.unlink(temp_file.name) # Clean up
301
+ return result.json()
302
+ except Exception as e:
303
+ os.unlink(temp_file.name) # Clean up on error
304
+ raise HTTPException(status_code=500, detail=str(e))
305
+
306
+ @app.get("/files")
307
+ async def list_files(page: int = 1, limit: int = 10):
308
+ try:
309
+ result = client.list_uploads(page=page, limit=limit)
310
+ return result.json()
311
+ except Exception as e:
312
+ raise HTTPException(status_code=500, detail=str(e))
313
+ ```
314
+
315
+ ## API Reference
316
+
317
+ ### Constructor
318
+ ```python
319
+ PinarkiveClient(token: Optional[str] = None, api_key: Optional[str] = None, base_url: str = 'https://api.pinarkive.com/api/v2')
320
+ ```
321
+ - `token`: Optional JWT token for authentication
322
+ - `api_key`: Optional API key for authentication
323
+ - `base_url`: Base URL for the API (defaults to production)
324
+
325
+ ### File Operations
326
+ - `upload_file(file_path: str)` - Upload single file
327
+ - `upload_directory(dir_path: str)` - Upload directory from path
328
+ - `upload_directory_dag(files_dict: Dict[str, Any], dir_name: Optional[str] = None)` - Upload directory as DAG
329
+ - `upload_directory_cluster(files: List[Dict[str, Any]])` - Upload directory using cluster
330
+ - `upload_file_to_directory(file_path: str, dir_path: str)` - Add file to existing directory
331
+ - `rename_file(upload_id: str, new_name: str)` - Rename uploaded file
332
+ - `remove_file(cid: str)` - Remove file from storage
333
+
334
+ ### Pinning Operations
335
+ - `pin_cid(cid: str)` - Pin CID to account
336
+ - `pin_cid_with_name(cid: str, custom_name: Optional[str] = None)` - Pin CID with custom name
337
+
338
+ ### User Operations
339
+ - `get_profile()` - Get user profile
340
+ - `update_profile(data: Dict[str, Any])` - Update user profile
341
+ - `list_uploads(page: int = 1, limit: int = 10)` - List uploaded files
342
+ - `delete_upload(cid: str)` - Delete uploaded file
343
+ - `get_referrals()` - Get referral information
344
+
345
+ ### Token Management
346
+ - `generate_token(name: str, options: Optional[Dict[str, Any]] = None)` - Generate API key
347
+ - `list_tokens()` - List all API keys
348
+ - `revoke_token(name: str)` - Revoke API key
349
+
350
+ ### Authentication
351
+ - `login(email: str, password: str)` - Login with credentials
352
+ - `signup(data: Dict[str, Any], locale: Optional[str] = None, refCode: Optional[str] = None)` - Create new account
353
+ - `logout()` - Logout current session
354
+
355
+ ### Status & Monitoring
356
+ - `get_status(cid: str)` - Get file status
357
+ - `get_allocations(cid: str)` - Get storage allocations
358
+
359
+ ## Examples
360
+
361
+ ### Complete File Management Workflow
362
+ ```python
363
+ from pinarkive_client import PinarkiveClient
364
+
365
+ def manage_files():
366
+ client = PinarkiveClient(api_key="your-api-key")
367
+
368
+ try:
369
+ # 1. Upload a file
370
+ result = client.upload_file("document.pdf")
371
+ upload_data = result.json()
372
+ print(f"Uploaded: {upload_data['cid']}")
373
+
374
+ # 2. Pin the CID with a custom name
375
+ pin_result = client.pin_cid_with_name(upload_data['cid'], "important-document")
376
+ print(f"Pinned: {pin_result.json()['pinned']}")
377
+
378
+ # 3. Rename the file
379
+ if 'uploadId' in upload_data:
380
+ rename_result = client.rename_file(upload_data['uploadId'], "my-document.pdf")
381
+ print(f"Renamed: {rename_result.json()['updated']}")
382
+
383
+ # 4. List all uploads
384
+ uploads = client.list_uploads()
385
+ print(f"All uploads: {uploads.json()['uploads']}")
386
+
387
+ except Exception as e:
388
+ print(f"Error: {e}")
389
+
390
+ manage_files()
391
+ ```
392
+
393
+ ### Directory Upload Workflow
394
+ ```python
395
+ def upload_project():
396
+ client = PinarkiveClient(api_key="your-api-key")
397
+
398
+ # Create project structure
399
+ project_files = {
400
+ "src/main.py": "print('Hello World')",
401
+ "src/utils.py": "def helper(): pass",
402
+ "requirements.txt": "requests>=2.31.0",
403
+ "README.md": "# My Project\n\nThis is my project."
404
+ }
405
+
406
+ try:
407
+ result = client.upload_directory_dag(project_files, dir_name="my-project")
408
+ response_data = result.json()
409
+ print(f"Project uploaded: {response_data['dagCid']}")
410
+ print(f"Files: {response_data['files']}")
411
+ except Exception as e:
412
+ print(f"Upload failed: {e}")
413
+
414
+ upload_project()
415
+ ```
416
+
417
+ ### Batch File Processing
418
+ ```python
419
+ import os
420
+ from pathlib import Path
421
+
422
+ def upload_directory_contents(directory_path: str):
423
+ client = PinarkiveClient(api_key="your-api-key")
424
+
425
+ files_dict = {}
426
+ directory = Path(directory_path)
427
+
428
+ # Recursively collect all files
429
+ for file_path in directory.rglob('*'):
430
+ if file_path.is_file():
431
+ # Get relative path from directory
432
+ relative_path = str(file_path.relative_to(directory))
433
+
434
+ # Read file content
435
+ with open(file_path, 'r', encoding='utf-8') as f:
436
+ content = f.read()
437
+
438
+ files_dict[relative_path] = content
439
+
440
+ try:
441
+ result = client.upload_directory_dag(files_dict, dir_name=directory.name)
442
+ print(f"Directory uploaded: {result.json()['dagCid']}")
443
+ except Exception as e:
444
+ print(f"Upload failed: {e}")
445
+
446
+ # Usage
447
+ upload_directory_contents("./my-project")
448
+ ```
449
+
450
+ ## Support
451
+
452
+ For issues or questions:
453
+ - GitHub Issues: [https://github.com/pinarkive/pinarkive-sdk/issues](https://github.com/pinarkive/pinarkive-sdk/issues)
454
+ - API Documentation: [https://api.pinarkive.com/docs](https://api.pinarkive.com/docs)
455
+ - Contact: [https://pinarkive.com/docs.php](https://pinarkive.com/docs.php)