cacheado 1.0.1__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.

Potentially problematic release.


This version of cacheado might be problematic. Click here for more details.

cacheado-1.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 George MendonΓ§a Silva de Morais
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,11 @@
1
+ include README.md
2
+ include LICENSE
3
+ include pyproject.toml
4
+ recursive-exclude tests *
5
+ recursive-exclude .github *
6
+ exclude .gitignore
7
+ exclude .pre-commit-config.yaml
8
+ exclude .flake8
9
+ exclude pytest.ini
10
+ exclude Makefile
11
+ exclude requirements.txt
@@ -0,0 +1,553 @@
1
+ Metadata-Version: 2.4
2
+ Name: cacheado
3
+ Version: 1.0.1
4
+ Summary: Advanced Python cache system with multi-tenant support, scope hierarchies, and configurable eviction policies
5
+ Author-email: George Mendonca Silva de Morais <george1bsilva@outlook.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/GeorgeOgeorge/cacheado
8
+ Project-URL: Repository, https://github.com/GeorgeOgeorge/cacheado
9
+ Project-URL: Documentation, https://github.com/GeorgeOgeorge/cacheado#readme
10
+ Project-URL: Bug Tracker, https://github.com/GeorgeOgeorge/cacheado/issues
11
+ Keywords: cache,multi-tenant,hierarchical,eviction,thread-safe
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
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
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Dynamic: license-file
25
+
26
+ # Hierarchical Multi-Tenant Cache System
27
+
28
+ An advanced Python cache system with support for scope hierarchies, configurable eviction policies, thread-safe operations, and cache stampede protection.
29
+
30
+ ## 🎯 Project Concept
31
+
32
+ This project implements an enterprise cache system that solves common problems in multi-tenant applications:
33
+
34
+ - **Data isolation** between different organizations/users
35
+ - **Intelligent memory management** with eviction policies
36
+ - **Cache stampede protection** in concurrent environments
37
+ - **Storage flexibility** through pluggable interfaces
38
+ - **Observability** with detailed metrics
39
+
40
+ ### Key Features
41
+
42
+ βœ… **Multi-Tenant**: Automatic isolation by organization, user, session, etc.
43
+ βœ… **Thread-Safe**: Atomic operations with granular locks
44
+ βœ… **Async/Sync**: Complete support for synchronous and asynchronous code
45
+ βœ… **Stampede Protection**: Prevents unnecessary recalculations in high concurrency
46
+ βœ… **Eviction Policies**: LRU implemented, extensible to LFU, FIFO, etc.
47
+ βœ… **Flexible TTL**: Automatic expiration with background cleanup
48
+ βœ… **Smart Decorator**: Transparent caching for functions
49
+ βœ… **Observability**: Metrics for hits, misses, evictions
50
+
51
+ ## πŸ—οΈ Architecture
52
+
53
+ The system follows the **Dependency Injection** pattern with well-defined interfaces:
54
+
55
+ ```
56
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
57
+ β”‚ Cache │────│ PolicyManager │────│ EvictionPolicy β”‚
58
+ β”‚ (Orchestrator) β”‚ β”‚ (Lifecycle) β”‚ β”‚ (LRU) β”‚
59
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
60
+ β”‚
61
+ β–Ό
62
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
63
+ β”‚ StorageProvider β”‚ β”‚ ScopeConfig β”‚
64
+ β”‚ (InMemory) β”‚ β”‚ (Hierarchies) β”‚
65
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
66
+ ```
67
+
68
+ ### Main Components
69
+
70
+ #### 1. **Cache (Central Orchestrator)**
71
+ - Coordinates all operations
72
+ - Manages stampede protection locks
73
+ - Maintains statistics (hits/misses/evictions)
74
+ - Delegates storage and policies
75
+
76
+ #### 2. **Storage Providers**
77
+ - **InMemory**: In-memory storage with per-key locks
78
+ - Extensible interface for Redis, Memcached, etc.
79
+
80
+ #### 3. **Eviction Policies**
81
+ - **LRU**: Least Recently Used implemented
82
+ - Interface for LFU, FIFO, TTL-based, etc.
83
+
84
+ #### 4. **Scope Configuration**
85
+ - Flexible hierarchies: `global β†’ org β†’ user β†’ session`
86
+ - Multiple independent trees
87
+ - Automatic parameter validation
88
+
89
+ #### 5. **Policy Manager**
90
+ - Manages background cleanup
91
+ - Coordinates global and per-namespace limits
92
+ - Daemon thread for automatic expiration
93
+
94
+ ## πŸ“Š Data Structures
95
+
96
+ ### Fundamental Types
97
+
98
+ ```python
99
+ # Internal cache key: (scope_path, namespace, args_hash)
100
+ _CacheKey = Tuple[str, str, Tuple[Any, ...]]
101
+
102
+ # Stored value: (data, expiry_timestamp)
103
+ _CacheValue = Tuple[Any, float]
104
+
105
+ # Scope: string or tuple of levels
106
+ _CacheScope = Union[str, Tuple[str, ...]]
107
+ ```
108
+
109
+ ### Internal Key Examples
110
+
111
+ ```python
112
+ # Global cache
113
+ ("global", "expensive_function", (b"pickled_args...",))
114
+
115
+ # Organization cache
116
+ ("organization:org_123", "user_data", (b"pickled_args...",))
117
+
118
+ # User cache
119
+ ("organization:org_123/user:user_456", "preferences", (b"pickled_args...",))
120
+
121
+ # Programmatic cache
122
+ ("organization:org_123", "__programmatic__", ("user_settings",))
123
+ ```
124
+
125
+ ### Scope Hierarchy
126
+
127
+ ```python
128
+ # Example configuration
129
+ scope_config = ScopeConfig([
130
+ ScopeLevel("organization", "org_id", [
131
+ ScopeLevel("user", "user_id", [
132
+ ScopeLevel("session", "session_id")
133
+ ])
134
+ ]),
135
+ ScopeLevel("tenant", "tenant_id", [
136
+ ScopeLevel("project", "project_id")
137
+ ])
138
+ ])
139
+
140
+ # Results in paths like:
141
+ # "global"
142
+ # "organization:123"
143
+ # "organization:123/user:456"
144
+ # "organization:123/user:456/session:789"
145
+ # "tenant:abc/project:xyz"
146
+ ```
147
+
148
+ ## πŸš€ Basic Usage
149
+
150
+ ### Initial Setup
151
+
152
+ ```python
153
+ from cache import create_cache
154
+ from storages.in_memory import InMemory
155
+ from eviction_policies.lre_eviction import LRUEvictionPolicy
156
+ from cache_policies.cache_policy_manager import CachePolicyManager
157
+ from cache_scopes.scope_config import ScopeConfig, ScopeLevel
158
+
159
+ # Configure scope hierarchy
160
+ scope_config = ScopeConfig([
161
+ ScopeLevel("organization", "org_id", [
162
+ ScopeLevel("user", "user_id")
163
+ ])
164
+ ])
165
+
166
+ # Create components
167
+ storage = InMemory()
168
+ eviction_policy = LRUEvictionPolicy()
169
+ policy_manager = CachePolicyManager(
170
+ cache_instance=None, # Will be set automatically
171
+ cleanup_interval=60, # Cleanup every 60 seconds
172
+ policy=eviction_policy,
173
+ max_size=10000 # Maximum 10k items globally
174
+ )
175
+
176
+ # Create and configure cache
177
+ cache = create_cache(
178
+ backend=storage,
179
+ policy_manager=policy_manager,
180
+ scope_config=scope_config
181
+ )
182
+ ```
183
+
184
+ ### Cache with Decorator
185
+
186
+ ```python
187
+ # Simple global cache
188
+ @cache.cache(ttl_seconds=300, scope="global")
189
+ def expensive_calculation(x, y):
190
+ time.sleep(2) # Simulate expensive operation
191
+ return x * y + random.random()
192
+
193
+ # User-scoped cache
194
+ @cache.cache(ttl_seconds=600, scope="user", max_items=100)
195
+ def get_user_preferences(user_data, organization_id=None, user_id=None):
196
+ # organization_id and user_id are automatically extracted for scope
197
+ return fetch_preferences_from_db(user_data)
198
+
199
+ # Async cache
200
+ @cache.cache(ttl_seconds=180, scope="organization")
201
+ async def fetch_org_data(org_slug, organization_id=None):
202
+ async with httpx.AsyncClient() as client:
203
+ response = await client.get(f"/api/orgs/{org_slug}")
204
+ return response.json()
205
+ ```
206
+
207
+ ### Programmatic Cache
208
+
209
+ ```python
210
+ # Synchronous operations
211
+ cache.set("user_settings", {"theme": "dark"}, 3600,
212
+ scope="user", organization_id="org_123", user_id="user_456")
213
+
214
+ settings = cache.get("user_settings",
215
+ scope="user", organization_id="org_123", user_id="user_456")
216
+
217
+ # Asynchronous operations
218
+ await cache.aset("session_data", {"cart": []}, 1800,
219
+ scope="session", organization_id="org_123",
220
+ user_id="user_456", session_id="sess_789")
221
+
222
+ data = await cache.aget("session_data",
223
+ scope="session", organization_id="org_123",
224
+ user_id="user_456", session_id="sess_789")
225
+ ```
226
+
227
+ ### Scope-based Eviction
228
+
229
+ ```python
230
+ # Remove all data from an organization
231
+ evicted_count = cache.evict_by_scope("organization", organization_id="org_123")
232
+
233
+ # Remove data from a specific user
234
+ cache.evict_by_scope("user", organization_id="org_123", user_id="user_456")
235
+
236
+ # Clear everything
237
+ cache.clear()
238
+ ```
239
+
240
+ ## πŸ“ˆ Observability
241
+
242
+ ### Available Metrics
243
+
244
+ ```python
245
+ stats = cache.stats()
246
+ print(stats)
247
+ # {
248
+ # "hits": 1250,
249
+ # "misses": 180,
250
+ # "evictions": 45,
251
+ # "current_size": 8934,
252
+ # "tracked_namespaces": 23,
253
+ # "total_calc_locks": 12
254
+ # }
255
+
256
+ # Hit rate
257
+ hit_rate = stats["hits"] / (stats["hits"] + stats["misses"])
258
+ print(f"Hit Rate: {hit_rate:.2%}")
259
+ ```
260
+
261
+ ### Structured Logs
262
+
263
+ ```python
264
+ import logging
265
+ logging.basicConfig(level=logging.INFO)
266
+
267
+ # The system generates logs for:
268
+ # - Cache hits/misses
269
+ # - Automatic evictions
270
+ # - Background cleanup
271
+ # - Serialization errors
272
+ # - Configuration operations
273
+ ```
274
+
275
+ ## πŸ”§ Advanced Configuration
276
+
277
+ ### Custom Limits
278
+
279
+ ```python
280
+ # Global limit
281
+ policy_manager = CachePolicyManager(
282
+ cache_instance=cache,
283
+ cleanup_interval=30,
284
+ policy=LRUEvictionPolicy(),
285
+ max_size=50000 # Maximum 50k items
286
+ )
287
+
288
+ # Per-function/namespace limit
289
+ @cache.cache(ttl_seconds=300, scope="global", max_items=1000)
290
+ def limited_function():
291
+ pass
292
+ ```
293
+
294
+ ### Multiple Hierarchies
295
+
296
+ ```python
297
+ # Support for multiple independent scope trees
298
+ scope_config = ScopeConfig([
299
+ # User tree
300
+ ScopeLevel("organization", "org_id", [
301
+ ScopeLevel("user", "user_id", [
302
+ ScopeLevel("session", "session_id")
303
+ ])
304
+ ]),
305
+ # Resource tree
306
+ ScopeLevel("tenant", "tenant_id", [
307
+ ScopeLevel("project", "project_id", [
308
+ ScopeLevel("environment", "env_id")
309
+ ])
310
+ ])
311
+ ])
312
+ ```
313
+
314
+ ### Custom Serialization
315
+
316
+ ```python
317
+ # The system uses pickle by default, but can be extended
318
+ class CustomCache(Cache):
319
+ def _make_args_key(self, *args, **kwargs):
320
+ # Custom implementation for specific types
321
+ try:
322
+ return super()._make_args_key(*args, **kwargs)
323
+ except TypeError:
324
+ # Fallback for non-pickleable types
325
+ return (str(args), str(sorted(kwargs.items())))
326
+ ```
327
+
328
+ ## πŸš€ CI/CD Pipeline
329
+
330
+ The project includes automated CI/CD pipeline with GitHub Actions for quality assurance and publishing:
331
+
332
+ ### Pipeline Stages
333
+
334
+ #### 1. **Quality Assurance** (`.github/workflows/quality.yml`)
335
+ Runs on every push and pull request:
336
+ - **Linting**: Code style validation with flake8
337
+ - **Formatting**: Black and isort checks
338
+ - **Type Checking**: MyPy static analysis
339
+ - **Standards**: Ensures code quality before merge
340
+
341
+ #### 2. **Automated Publishing** (`.github/workflows/publish.yml`)
342
+ Triggered on push/merge to `master` branch:
343
+
344
+ **Pipeline Steps:**
345
+ 1. **Test Execution**: Full test suite with coverage
346
+ 2. **Quality Validation**: Lint, format, and type checks
347
+ 3. **Version Validation**: Ensures version was bumped
348
+ 4. **Package Building**: Creates distribution files
349
+ 5. **Git Tagging**: Automatic version tagging
350
+ 6. **GitHub Release**: Creates release with notes
351
+ 7. **PyPI Publishing**: Uploads to Python Package Index
352
+
353
+ ### Version Management
354
+
355
+ ```bash
356
+ # Bump version before merge/push
357
+ make bump-patch # 1.0.0 β†’ 1.0.1 (bug fixes)
358
+ make bump-minor # 1.0.0 β†’ 1.1.0 (new features)
359
+ make bump-major # 1.0.0 β†’ 2.0.0 (breaking changes)
360
+ ```
361
+
362
+ ### Setup Requirements
363
+
364
+ 1. **PyPI API Token**: Add `PYPI_API_TOKEN` to GitHub repository secrets
365
+ 2. **Version Bump**: Always increment version before merge to master
366
+ 3. **Quality Gates**: All tests and quality checks must pass
367
+
368
+ ### Manual Publishing
369
+
370
+ ```bash
371
+ # Local development workflow
372
+ make test-coverage # Ensure tests pass
373
+ make quality-check # Validate code quality
374
+ make bump-patch # Increment version
375
+ make build # Build package locally
376
+ make publish-test # Test on TestPyPI
377
+ make publish # Publish to PyPI
378
+ ```
379
+
380
+ ## πŸ§ͺ Tests
381
+
382
+ The project includes a complete test suite:
383
+
384
+ ```bash
385
+ # Run all tests
386
+ make test
387
+
388
+ # Specific tests
389
+ make test-unit # Unit tests only
390
+ make test-integration # Integration tests
391
+ make test-performance # Performance tests
392
+
393
+ # With coverage
394
+ make test-coverage
395
+ ```
396
+
397
+ ### Test Structure
398
+
399
+ - **Unit Tests**: Each component in isolation
400
+ - **Integration Tests**: Complete system working together
401
+ - **Performance Tests**: Benchmarks and stress tests
402
+ - **Concurrency Tests**: Thread safety and race conditions
403
+
404
+ ## πŸ”’ Thread Safety
405
+
406
+ ### Synchronization Strategies
407
+
408
+ 1. **Per-Key Locks**: Each key has its own lock
409
+ 2. **Instance Lock**: For global operations (clear, stats)
410
+ 3. **Calculation Locks**: Stampede protection per function
411
+ 4. **Atomic Operations**: Thread-safe storage providers
412
+
413
+ ### Stampede Protection
414
+
415
+ ```python
416
+ # Multiple threads calling the same function simultaneously
417
+ # Only one executes, others wait for the result
418
+
419
+ @cache.cache(ttl_seconds=300)
420
+ def expensive_api_call(endpoint):
421
+ # Only one thread will execute this at a time for the same endpoint
422
+ return requests.get(endpoint).json()
423
+
424
+ # 100 simultaneous threads = 1 API call
425
+ results = await asyncio.gather(*[
426
+ expensive_api_call("/api/data") for _ in range(100)
427
+ ])
428
+ ```
429
+
430
+ ## πŸš€ Performance
431
+
432
+ ### Typical Benchmarks
433
+
434
+ - **Basic operations**: >10,000 ops/sec
435
+ - **Concurrent operations**: >5,000 ops/sec
436
+ - **Memory usage**: <500MB for 50k items
437
+ - **Latency**: <1ms for hits, <10ms for misses
438
+
439
+ ### Optimizations
440
+
441
+ - `__slots__` for memory efficiency
442
+ - Granular locks for high concurrency
443
+ - Optimized serialization with pickle
444
+ - Non-blocking background cleanup
445
+
446
+ ## πŸ”Œ Extensibility
447
+
448
+ ### New Storage Providers
449
+
450
+ ```python
451
+ class RedisStorage(IStorageProvider):
452
+ def __init__(self, redis_client):
453
+ self.redis = redis_client
454
+
455
+ def get(self, key: _CacheKey) -> Optional[_CacheValue]:
456
+ # Redis implementation
457
+ pass
458
+ ```
459
+
460
+ ### New Eviction Policies
461
+
462
+ ```python
463
+ class LFUEvictionPolicy(IEvictionPolicy):
464
+ def notify_set(self, key, namespace, max_items, global_max_size):
465
+ # Least Frequently Used implementation
466
+ pass
467
+ ```
468
+
469
+ ## πŸ“ License
470
+
471
+ This project is open source and available under the MIT license.
472
+
473
+ ## 🀝 Contributing
474
+
475
+ ### Development Workflow
476
+
477
+ 1. **Fork and Clone**
478
+ ```bash
479
+ git clone https://github.com/yourusername/cacheado.git
480
+ cd cacheado
481
+ ```
482
+
483
+ 2. **Create Feature Branch**
484
+ ```bash
485
+ git checkout -b feature/amazing-feature
486
+ ```
487
+
488
+ 3. **Development Cycle**
489
+ ```bash
490
+ # Install dependencies
491
+ pip install -r requirements.txt
492
+
493
+ # Run tests during development
494
+ make test-coverage
495
+
496
+ # Check code quality
497
+ make quality-check
498
+
499
+ # Format code
500
+ make format
501
+ ```
502
+
503
+ 4. **Pre-commit Validation**
504
+ ```bash
505
+ make check-all # Runs tests + quality checks
506
+ ```
507
+
508
+ 5. **Submit Changes**
509
+ ```bash
510
+ git commit -m "feat: add amazing feature"
511
+ git push origin feature/amazing-feature
512
+ ```
513
+
514
+ 6. **Create Pull Request**
515
+ - All CI checks must pass
516
+ - Maintain test coverage >95%
517
+ - Follow conventional commit messages
518
+
519
+ ### Release Process (Maintainers)
520
+
521
+ 1. **Prepare Release**
522
+ ```bash
523
+ make bump-minor # or bump-patch/bump-major
524
+ git add pyproject.toml
525
+ git commit -m "chore: bump version to X.Y.Z"
526
+ ```
527
+
528
+ 2. **Merge to Master**
529
+ - Pipeline automatically:
530
+ - Validates version bump
531
+ - Runs full test suite
532
+ - Creates Git tag
533
+ - Publishes to PyPI
534
+ - Creates GitHub release
535
+
536
+ ### Guidelines
537
+
538
+ - **Test Coverage**: Maintain >95% coverage
539
+ - **Code Style**: Follow Black + isort formatting
540
+ - **Type Hints**: Add type annotations for new code
541
+ - **Documentation**: Update README for new features
542
+ - **Commit Messages**: Use conventional commits format
543
+
544
+ ## πŸ“š Additional Documentation
545
+
546
+ - [Configuration Guide](docs/configuration.md)
547
+ - [API Reference](docs/api.md)
548
+ - [Advanced Examples](docs/examples.md)
549
+ - [Troubleshooting](docs/troubleshooting.md)
550
+
551
+ ---
552
+
553
+ **Developed with ❀️ for high-performance Python applications**