cacheado 1.0.1__py3-none-any.whl
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.
- cache.py +678 -0
- cache_policies/__init__.py +0 -0
- cache_policies/cache_policy_manager.py +187 -0
- cache_scopes/__init__.py +0 -0
- cache_scopes/scope_config.py +228 -0
- cache_types.py +6 -0
- cacheado-1.0.1.dist-info/METADATA +553 -0
- cacheado-1.0.1.dist-info/RECORD +21 -0
- cacheado-1.0.1.dist-info/WHEEL +5 -0
- cacheado-1.0.1.dist-info/licenses/LICENSE +21 -0
- cacheado-1.0.1.dist-info/top_level.txt +7 -0
- eviction_policies/__init__.py +0 -0
- eviction_policies/lre_eviction.py +130 -0
- protocols/__init__.py +0 -0
- protocols/cache.py +183 -0
- protocols/cache_policy_manager_protocol.py +82 -0
- protocols/eviction_policy.py +70 -0
- protocols/scope.py +85 -0
- protocols/storage_provider.py +67 -0
- storages/__init__.py +0 -0
- storages/in_memory.py +109 -0
|
@@ -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**
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
cache.py,sha256=jAmLgzHeO2Ekvjst_MQuwYaPedu8B4YZq7_Dx80jnBo,26281
|
|
2
|
+
cache_types.py,sha256=E2zNIu3mFc1JaCS1HCipRQt-nxvocAsLBFjur8WFSEw,229
|
|
3
|
+
cache_policies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
cache_policies/cache_policy_manager.py,sha256=-0SfUp1jEA6QA-Sz9MNxhfG07qdAIAo8LS_tnKrcTds,6736
|
|
5
|
+
cache_scopes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
cache_scopes/scope_config.py,sha256=3OxbRGG8JWlUQ3JDmWgX4FfiIK8HLJhBJfKtYhw-m18,7812
|
|
7
|
+
cacheado-1.0.1.dist-info/licenses/LICENSE,sha256=GvYcuDVEATNePcWXYEvSRFak2ZMGEwdtJs60Ldh8mHk,1088
|
|
8
|
+
eviction_policies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
eviction_policies/lre_eviction.py,sha256=e4QwXDHNTjYwMEm0q6RCjUlVFgKk1RA0mCAUSK3HtK4,4800
|
|
10
|
+
protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
protocols/cache.py,sha256=hR_MvXjoQIBnnRujWWedvUHGoDRRi07iwYPcFW6T_5s,6571
|
|
12
|
+
protocols/cache_policy_manager_protocol.py,sha256=Ps0tyC1Oz3DAqzAqg5rMsjOUrMQN33a5t9JFmgWreOg,2236
|
|
13
|
+
protocols/eviction_policy.py,sha256=2ubG8YSKM023bKjKhHauHm9lpLmVBG6LZc83Hx9KQn4,2019
|
|
14
|
+
protocols/scope.py,sha256=HCVGgtFr1Ty80__4Jrd__ba2flxhBs9LPaH7pSwJvrg,2178
|
|
15
|
+
protocols/storage_provider.py,sha256=G0_RTlFt5FzfQdqB3lZco2SezZECe8BK2Rs-2lj4A4U,1810
|
|
16
|
+
storages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
storages/in_memory.py,sha256=QD0bMU-Nx6rCsecame8QC__x-sDmF7yURf1fswAHWgk,3465
|
|
18
|
+
cacheado-1.0.1.dist-info/METADATA,sha256=MSbK0WNhL5zCkajT6jEMKGvtlFUPosIPcGEAZuG-_TM,15629
|
|
19
|
+
cacheado-1.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
20
|
+
cacheado-1.0.1.dist-info/top_level.txt,sha256=u2Qmb95sr-ThDFMMpCy3vXTYY0vZpBesv2c4fWobO9w,83
|
|
21
|
+
cacheado-1.0.1.dist-info/RECORD,,
|
|
@@ -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.
|
|
File without changes
|