genro-storage 0.1.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 (30) hide show
  1. genro_storage-0.1.0/LICENSE +21 -0
  2. genro_storage-0.1.0/MANIFEST.in +7 -0
  3. genro_storage-0.1.0/PKG-INFO +380 -0
  4. genro_storage-0.1.0/README.md +327 -0
  5. genro_storage-0.1.0/genro_storage/__init__.py +58 -0
  6. genro_storage-0.1.0/genro_storage/backends/__init__.py +21 -0
  7. genro_storage-0.1.0/genro_storage/backends/base.py +534 -0
  8. genro_storage-0.1.0/genro_storage/backends/base64.py +395 -0
  9. genro_storage-0.1.0/genro_storage/backends/fsspec.py +647 -0
  10. genro_storage-0.1.0/genro_storage/backends/local.py +307 -0
  11. genro_storage-0.1.0/genro_storage/exceptions.py +82 -0
  12. genro_storage-0.1.0/genro_storage/manager.py +514 -0
  13. genro_storage-0.1.0/genro_storage/node.py +1319 -0
  14. genro_storage-0.1.0/genro_storage/py.typed +1 -0
  15. genro_storage-0.1.0/genro_storage.egg-info/PKG-INFO +380 -0
  16. genro_storage-0.1.0/genro_storage.egg-info/SOURCES.txt +29 -0
  17. genro_storage-0.1.0/genro_storage.egg-info/dependency_links.txt +1 -0
  18. genro_storage-0.1.0/genro_storage.egg-info/requires.txt +34 -0
  19. genro_storage-0.1.0/genro_storage.egg-info/top_level.txt +1 -0
  20. genro_storage-0.1.0/pyproject.toml +101 -0
  21. genro_storage-0.1.0/requirements-docs.txt +5 -0
  22. genro_storage-0.1.0/setup.cfg +12 -0
  23. genro_storage-0.1.0/tests/test_advanced_features.py +545 -0
  24. genro_storage-0.1.0/tests/test_base64.py +369 -0
  25. genro_storage-0.1.0/tests/test_call_and_mimetype.py +332 -0
  26. genro_storage-0.1.0/tests/test_copy_skip_strategies.py +416 -0
  27. genro_storage-0.1.0/tests/test_local_storage.py +484 -0
  28. genro_storage-0.1.0/tests/test_md5_and_equality.py +295 -0
  29. genro_storage-0.1.0/tests/test_s3_integration.py +272 -0
  30. genro_storage-0.1.0/tests/test_serve.py +331 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Genropy Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ include README.md
2
+ include LICENSE
3
+ include pyproject.toml
4
+ include requirements-docs.txt
5
+ recursive-include genro_storage *.py py.typed
6
+ recursive-exclude * __pycache__
7
+ recursive-exclude * *.py[co]
@@ -0,0 +1,380 @@
1
+ Metadata-Version: 2.4
2
+ Name: genro-storage
3
+ Version: 0.1.0
4
+ Summary: Unified storage abstraction for Genropy framework
5
+ Author-email: Genropy Team <info@genropy.org>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/genropy/genro-storage
8
+ Project-URL: Documentation, https://genro-storage.readthedocs.io
9
+ Project-URL: Repository, https://github.com/genropy/genro-storage
10
+ Project-URL: Bug Tracker, https://github.com/genropy/genro-storage/issues
11
+ Keywords: storage,filesystem,s3,cloud,genropy
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: System :: Filesystems
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: fsspec>=2023.1.0
26
+ Requires-Dist: PyYAML>=6.0
27
+ Provides-Extra: s3
28
+ Requires-Dist: s3fs>=2023.1.0; extra == "s3"
29
+ Provides-Extra: gcs
30
+ Requires-Dist: gcsfs>=2023.1.0; extra == "gcs"
31
+ Provides-Extra: azure
32
+ Requires-Dist: adlfs>=2023.1.0; extra == "azure"
33
+ Provides-Extra: http
34
+ Requires-Dist: aiohttp>=3.8.0; extra == "http"
35
+ Provides-Extra: all
36
+ Requires-Dist: s3fs>=2023.1.0; extra == "all"
37
+ Requires-Dist: gcsfs>=2023.1.0; extra == "all"
38
+ Requires-Dist: adlfs>=2023.1.0; extra == "all"
39
+ Requires-Dist: aiohttp>=3.8.0; extra == "all"
40
+ Provides-Extra: docs
41
+ Requires-Dist: sphinx>=7.0; extra == "docs"
42
+ Requires-Dist: sphinx-rtd-theme>=2.0; extra == "docs"
43
+ Requires-Dist: sphinx-autodoc-typehints>=1.24; extra == "docs"
44
+ Requires-Dist: myst-parser>=2.0; extra == "docs"
45
+ Provides-Extra: dev
46
+ Requires-Dist: pytest>=7.0; extra == "dev"
47
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
48
+ Requires-Dist: black>=23.0; extra == "dev"
49
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
50
+ Requires-Dist: mypy>=1.0; extra == "dev"
51
+ Requires-Dist: boto3>=1.26.0; extra == "dev"
52
+ Dynamic: license-file
53
+
54
+ # genro-storage
55
+
56
+ [![Python versions](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/downloads/)
57
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
58
+ [![Documentation Status](https://readthedocs.org/projects/genro-storage/badge/?version=latest)](https://genro-storage.readthedocs.io/en/latest/?badge=latest)
59
+ [![Tests](https://github.com/genropy/genro-storage/workflows/Tests/badge.svg)](https://github.com/genropy/genro-storage/actions)
60
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
61
+
62
+ **Universal storage abstraction for Python with pluggable backends**
63
+
64
+ A modern, elegant Python library that provides a unified interface for accessing files across local filesystems, cloud storage (S3, GCS, Azure), and remote protocols (HTTP). Built on top of **fsspec**, genro-storage adds an intuitive mount-point system and user-friendly API inspired by Unix filesystems.
65
+
66
+ ## Status: Beta - Ready for Production Testing
67
+
68
+ **Current Version:** 0.1.0-beta
69
+ **Last Updated:** October 2025
70
+
71
+ ✅ Core implementation complete
72
+ ✅ All backends working (local, S3, GCS, Azure, HTTP, Memory, Base64)
73
+ ✅ 195 tests passing on Python 3.9-3.12
74
+ ✅ Full documentation on ReadTheDocs
75
+ ✅ Battle-tested code from 6+ years of Genropy production use
76
+ ⚠️ Not yet on PyPI - install from source
77
+
78
+ ## Key Features
79
+
80
+ - **Powered by fsspec** - Leverage 20+ battle-tested storage backends
81
+ - **Mount point system** - Organize storage with logical names like `home:`, `uploads:`, `s3:`
82
+ - **Intuitive API** - Pathlib-inspired interface that feels natural and Pythonic
83
+ - **Intelligent copy strategies** - Skip files by existence, size, or hash for efficient incremental backups
84
+ - **Progress tracking** - Built-in callbacks for progress bars and logging during copy operations
85
+ - **Content-based comparison** - Compare files by MD5 hash across different backends
86
+ - **Efficient hashing** - Uses cloud metadata (S3 ETag) when available, avoiding downloads
87
+ - **External tool integration** - `call()` method for seamless integration with ffmpeg, imagemagick, pandoc, etc.
88
+ - **WSGI file serving** - `serve()` method for web frameworks (Flask, Django, Pyramid) with ETag caching
89
+ - **MIME type detection** - Automatic content-type detection from file extensions
90
+ - **Flexible configuration** - Load mounts from YAML, JSON, or code
91
+ - **Dynamic paths** - Support for callable paths that resolve at runtime (perfect for user-specific directories)
92
+ - **Cloud metadata** - Get/set custom metadata on S3, GCS, Azure files
93
+ - **URL generation** - Generate presigned URLs for S3, public URLs for sharing
94
+ - **Base64 utilities** - Encode files to data URIs, download from URLs
95
+ - **S3 versioning** - Access historical file versions (when S3 versioning enabled)
96
+ - **Test-friendly** - In-memory backend for fast, isolated testing
97
+ - **Base64 data URIs** - Embed data inline with automatic encoding (writable with mutable paths)
98
+ - **Production-ready backends** - Built on 6+ years of Genropy production experience
99
+ - **Lightweight core** - Optional backends installed only when needed
100
+ - **Cross-storage operations** - Copy/move files between different storage types seamlessly
101
+
102
+ ## Why genro-storage vs raw fsspec?
103
+
104
+ While **fsspec** is powerful, genro-storage provides:
105
+
106
+ - **Mount point abstraction** - Work with logical names instead of full URIs
107
+ - **Simpler API** - Less verbose, more intuitive for common operations
108
+ - **Configuration management** - Load storage configs from files
109
+ - **Enhanced utilities** - Cross-storage copy, unified error handling
110
+
111
+ Think of it as **"requests" is to "urllib"** - a friendlier interface to an excellent foundation.
112
+
113
+ ## Perfect For
114
+
115
+ - **Multi-cloud applications** that need storage abstraction
116
+ - **Data pipelines** processing files from various sources
117
+ - **Web applications** managing uploads across environments
118
+ - **CLI tools** that work with local and remote files
119
+ - **Testing scenarios** requiring storage mocking
120
+
121
+ ## Quick Example
122
+
123
+ ```python
124
+ from genro_storage import StorageManager
125
+
126
+ # Configure storage backends
127
+ storage = StorageManager()
128
+ storage.configure([
129
+ {'name': 'home', 'type': 'local', 'path': '/home/user'},
130
+ {'name': 'uploads', 'type': 's3', 'bucket': 'my-app-uploads'},
131
+ {'name': 'backups', 'type': 'gcs', 'bucket': 'my-backups'},
132
+ {'name': 'data', 'type': 'base64'} # Inline base64 data
133
+ ])
134
+
135
+ # Work with files using a unified API
136
+ node = storage.node('uploads:users/123/avatar.jpg')
137
+ if node.exists:
138
+ # Copy from S3 to local
139
+ node.copy(storage.node('home:cache/avatar.jpg'))
140
+
141
+ # Read and process
142
+ data = node.read_bytes()
143
+
144
+ # Backup to GCS
145
+ node.copy(storage.node('backups:avatars/user_123.jpg'))
146
+
147
+ # Base64 backend: embed data directly in URIs (data URI style)
148
+ # Read inline data
149
+ import base64
150
+ text = "Configuration data"
151
+ b64_data = base64.b64encode(text.encode()).decode()
152
+ node = storage.node(f'data:{b64_data}')
153
+ print(node.read_text()) # "Configuration data"
154
+
155
+ # Or write to create base64 (path updates automatically)
156
+ node = storage.node('data:')
157
+ node.write_text("New content")
158
+ print(node.path) # "TmV3IGNvbnRlbnQ=" (base64 of "New content")
159
+
160
+ # Copy from S3 to base64 for inline use
161
+ s3_image = storage.node('uploads:photo.jpg')
162
+ b64_image = storage.node('data:')
163
+ s3_image.copy(b64_image)
164
+ data_uri = f"data:image/jpeg;base64,{b64_image.path}"
165
+
166
+ # Advanced features
167
+ # 1. Intelligent incremental backups (NEW!)
168
+ docs = storage.node('home:documents')
169
+ s3_backup = storage.node('uploads:backup/documents')
170
+
171
+ # Skip files that already exist (fastest)
172
+ docs.copy(s3_backup, skip='exists')
173
+
174
+ # Skip files with same size (fast, good accuracy)
175
+ docs.copy(s3_backup, skip='size')
176
+
177
+ # Skip files with same content (accurate, uses S3 ETag - fast!)
178
+ docs.copy(s3_backup, skip='hash')
179
+
180
+ # With progress tracking
181
+ from tqdm import tqdm
182
+ pbar = tqdm(desc="Backing up", unit="file")
183
+ docs.copy(s3_backup, skip='hash',
184
+ progress=lambda cur, tot: pbar.update(1))
185
+ pbar.close()
186
+
187
+ # 2. Work with external tools using call() (ffmpeg, imagemagick, etc.)
188
+ video = storage.node('uploads:video.mp4')
189
+ thumbnail = storage.node('uploads:thumb.jpg')
190
+
191
+ # Automatically handles cloud download/upload
192
+ video.call('ffmpeg', '-i', video, '-vf', 'thumbnail', '-frames:v', '1', thumbnail)
193
+
194
+ # Or use local_path() for more control
195
+ with video.local_path(mode='r') as local_path:
196
+ import subprocess
197
+ subprocess.run(['ffmpeg', '-i', local_path, 'output.mp4'])
198
+
199
+ # 3. Serve files via WSGI (Flask, Django, Pyramid)
200
+ from flask import Flask, request
201
+ app = Flask(__name__)
202
+
203
+ @app.route('/files/<path:filepath>')
204
+ def serve_file(filepath):
205
+ node = storage.node(f'uploads:{filepath}')
206
+ # ETag caching, streaming, MIME types - all automatic!
207
+ return node.serve(request.environ, lambda s, h: None, cache_max_age=3600)
208
+
209
+ # 4. Check MIME types
210
+ doc = storage.node('uploads:report.pdf')
211
+ print(doc.mimetype) # 'application/pdf'
212
+
213
+ # 5. Dynamic paths for multi-user apps
214
+ def get_user_storage():
215
+ user_id = get_current_user()
216
+ return f'/data/users/{user_id}'
217
+
218
+ storage.configure([
219
+ {'name': 'user', 'type': 'local', 'path': get_user_storage}
220
+ ])
221
+ # Path resolves differently per user!
222
+
223
+ # 6. Cloud metadata
224
+ file = storage.node('uploads:document.pdf')
225
+ file.set_metadata({
226
+ 'Author': 'John Doe',
227
+ 'Department': 'Engineering'
228
+ })
229
+
230
+ # 7. Generate shareable URLs
231
+ url = file.url(expires_in=3600) # S3 presigned URL
232
+
233
+ # 8. Encode to data URI
234
+ img = storage.node('home:logo.png')
235
+ data_uri = img.to_base64() # data:image/png;base64,...
236
+
237
+ # 9. Download from internet
238
+ remote = storage.node('uploads:downloaded.pdf')
239
+ remote.fill_from_url('https://example.com/file.pdf')
240
+ ```
241
+
242
+ ## Installation
243
+
244
+ ### From GitHub (Recommended)
245
+
246
+ Install directly from GitHub without cloning:
247
+
248
+ ```bash
249
+ # Base package
250
+ pip install git+https://github.com/genropy/genro-storage.git
251
+
252
+ # With S3 support
253
+ pip install "genro-storage[s3] @ git+https://github.com/genropy/genro-storage.git"
254
+
255
+ # With all backends
256
+ pip install "genro-storage[all] @ git+https://github.com/genropy/genro-storage.git"
257
+ ```
258
+
259
+ ### From Source (Development)
260
+
261
+ Clone and install in editable mode:
262
+
263
+ ```bash
264
+ # Clone repository
265
+ git clone https://github.com/genropy/genro-storage.git
266
+ cd genro-storage
267
+
268
+ # Install base package
269
+ pip install -e .
270
+
271
+ # Install with S3 support
272
+ pip install -e ".[s3]"
273
+
274
+ # Install with all backends
275
+ pip install -e ".[all]"
276
+
277
+ # Install for development
278
+ pip install -e ".[all,dev]"
279
+ ```
280
+
281
+ ### Supported Backends
282
+
283
+ Install optional dependencies for specific backends:
284
+
285
+ ```bash
286
+ pip install genro-storage[s3] # Amazon S3
287
+ pip install genro-storage[gcs] # Google Cloud Storage
288
+ pip install genro-storage[azure] # Azure Blob Storage
289
+ pip install genro-storage[http] # HTTP/HTTPS
290
+ pip install genro-storage[all] # All backends
291
+ ```
292
+
293
+ ## Testing
294
+
295
+ ```bash
296
+ # Unit tests (fast, no external dependencies)
297
+ pytest tests/test_local_storage.py -v
298
+
299
+ # Integration tests (requires Docker + MinIO)
300
+ docker-compose up -d
301
+ pytest tests/test_s3_integration.py -v
302
+
303
+ # All tests
304
+ pytest tests/ -v
305
+
306
+ # With coverage
307
+ pytest tests/ -v --cov=genro_storage
308
+ ```
309
+
310
+ See [TESTING.md](TESTING.md) for detailed testing instructions with MinIO.
311
+
312
+ ## Documentation
313
+
314
+ - **[Full Documentation](https://genro-storage.readthedocs.io/)** - Complete API reference and guides
315
+ - **[API Design](API_DESIGN.md)** - Detailed design specification
316
+ - **[Testing Guide](TESTING.md)** - How to run tests with MinIO
317
+
318
+ ## Built With
319
+
320
+ - [fsspec](https://filesystem-spec.readthedocs.io/) - Pythonic filesystem abstraction
321
+ - Modern Python (3.9+) with full type hints
322
+ - Optional backends: s3fs, gcsfs, adlfs, aiohttp
323
+
324
+ ## Origins
325
+
326
+ genro-storage is extracted and modernized from [Genropy](https://github.com/genropy/genropy), a Python web framework with 6+ years of production battle-testing. We're making this powerful storage abstraction available as a standalone library for the wider Python community.
327
+
328
+ ## Development Status
329
+
330
+ **Phase:** Beta - Production Testing
331
+
332
+ - ✅ API Design Complete and Stable
333
+ - ✅ Core Implementation Complete
334
+ - ✅ FsspecBackend (all 7 storage types working: local, S3, GCS, Azure, HTTP, Memory, Base64)
335
+ - ✅ Comprehensive Test Suite (195 tests, 79% coverage)
336
+ - ✅ CI/CD with Python 3.9, 3.10, 3.11, 3.12
337
+ - ✅ MD5 hashing and content-based equality
338
+ - ✅ Base64 backend with writable mutable paths
339
+ - ✅ Intelligent copy skip strategies (exists, size, hash, custom)
340
+ - ✅ call() method for external tool integration (ffmpeg, imagemagick, etc.)
341
+ - ✅ serve() method for WSGI file serving (Flask, Django, Pyramid)
342
+ - ✅ mimetype property for automatic content-type detection
343
+ - ✅ local_path() context manager for external tools
344
+ - ✅ Callable path support for dynamic directories
345
+ - ✅ Cloud metadata get/set (S3, GCS, Azure)
346
+ - ✅ URL generation (presigned URLs, data URIs)
347
+ - ✅ S3 versioning support
348
+ - ✅ Full Documentation on ReadTheDocs
349
+ - ✅ MinIO Integration Testing
350
+ - 🎯 Ready for early adopters and production testing
351
+ - ⏳ First PyPI release (v0.1.0)
352
+ - ⏳ Extended GCS/Azure integration testing
353
+
354
+ **Roadmap:**
355
+ - v0.1.0 (Q4 2025) - First PyPI release (Beta)
356
+ - v0.2.0 (Q1 2026) - Async support, performance optimizations
357
+ - v1.0.0 (2026) - Production-ready, stable API guarantee
358
+
359
+ ## Contributing
360
+
361
+ Contributions welcome! The library is in beta with a stable API.
362
+
363
+ **How to contribute:**
364
+ 1. Review the [API Design Document](API_DESIGN.md)
365
+ 2. Check existing [tests](tests/) to understand behavior
366
+ 3. Open an issue to discuss major changes
367
+ 4. Submit PRs with tests
368
+
369
+ **Testing contributions:**
370
+ - Add tests for GCS and Azure backends
371
+ - Improve test coverage (target: 90%+)
372
+ - Add integration tests for edge cases
373
+
374
+ ## License
375
+
376
+ MIT License - See [LICENSE](LICENSE) for details
377
+
378
+ ---
379
+
380
+ **Made with ❤️ by the Genropy team**