Skip to content

Commit 402a579

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent fcee1d8 commit 402a579

3 files changed

Lines changed: 56 additions & 21 deletions

File tree

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ When writing tests for cachier, follow these critical guidelines to ensure test
688688
689689
def test_feature_a():
690690
assert shared_func(5) == 10
691-
691+
692692
def test_feature_b():
693693
assert shared_func(5) == 10 # This may conflict with test_feature_a
694694

parallel_test_analysis.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,20 @@ The parallel tests for MongoDB, Redis, and SQL backends successfully avoid confl
77
### 1. **Unique Function Names Per Cache Key**
88

99
Cache keys in Cachier are generated using a combination of:
10+
1011
- **Module name**: `func.__module__`
1112
- **Function name**: `func.__name__`
1213
- **Function arguments**: Hashed via the `hash_func`
1314

1415
From `src/cachier/cores/base.py`:
16+
1517
```python
1618
def _get_func_str(func: Callable) -> str:
1719
return f".{func.__module__}.{func.__name__}"
1820
```
1921

2022
This means:
23+
2124
- Each backend prefixes cache entries with the full module path and function name
2225
- Redis: `{prefix}:{func_str}:{key}` (e.g., `cachier:.tests.test_redis_core._test_redis_caching:hash123`)
2326
- MongoDB: Documents with `{"func": func_str, "key": key}`
@@ -26,18 +29,21 @@ This means:
2629
### 2. **Function Name Isolation Within Test Files**
2730

2831
Looking at the test files:
32+
2933
- Functions within each test function are **locally scoped**
3034
- Even if multiple tests use `def f(x)` or `def _test_func()`, they are different function objects
3135
- Each function gets a unique module path because they're defined inside different test functions
3236

3337
Examples:
38+
3439
```python
3540
# In test_sql_core.py
3641
def test_sql_core_basic():
3742
@cachier(backend="sql", sql_engine=SQL_CONN_STR)
3843
def f(x, y): # This f is local to test_sql_core_basic
3944
return random() + x + y
4045

46+
4147
def test_sql_core_keywords():
4248
@cachier(backend="sql", sql_engine=SQL_CONN_STR)
4349
def f(x, y): # This f is different from the one above
@@ -47,27 +53,32 @@ def test_sql_core_keywords():
4753
### 3. **Clear Cache Operations**
4854

4955
Most tests start with `func.clear_cache()` which removes all entries for that specific function:
56+
5057
- MongoDB: `delete_many(filter={"func": self._func_str})`
5158
- Redis: Deletes all keys matching pattern `{prefix}:{func_str}:*`
5259
- SQL: `delete(CacheTable).where(CacheTable.function_id == self._func_str)`
5360

5461
### 4. **Backend-Specific Isolation**
5562

5663
#### MongoDB:
64+
5765
- Uses a collection name that includes platform and Python version: `cachier_test_{platform}_{python_version}`
5866
- Each function's entries are filtered by `func` field
5967

6068
#### Redis:
69+
6170
- Uses key prefixes that include the full function path
6271
- Pattern-based operations only affect keys for specific functions
6372

6473
#### SQL:
74+
6575
- Uses `function_id` column to separate entries by function
6676
- Composite operations use both `function_id` and `key`
6777

6878
### 5. **Test Fixtures for Additional Isolation**
6979

7080
From `tests/conftest.py`:
81+
7182
```python
7283
@pytest.fixture(autouse=True)
7384
def isolated_cache_directory(tmp_path, monkeypatch, request, worker_id):
@@ -83,6 +94,7 @@ def isolated_cache_directory(tmp_path, monkeypatch, request, worker_id):
8394
### 6. **No Shared Function Names Across Test Files**
8495

8596
Analysis shows:
97+
8698
- Test functions have unique names across files (no duplicate `test_*` function names)
8799
- Cached functions are either:
88100
- Defined locally within test functions (most common)
@@ -91,17 +103,19 @@ Analysis shows:
91103
### 7. **Argument-Based Key Differentiation**
92104

93105
Even if two tests used the same function name (which they don't), different arguments would create different cache keys:
106+
94107
- Tests use different argument values (e.g., `(1, 2)`, `(34, 82.3)`, etc.)
95108
- The hash function ensures different arguments → different keys
96109

97110
## Conclusion
98111

99112
The parallel tests avoid conflicts through:
113+
100114
1. **Function name namespacing** - Full module path included in cache keys
101115
2. **Local function scope** - Functions defined inside test functions are unique objects
102116
3. **Clear cache operations** - Tests clean up their own function's cache
103117
4. **Backend-specific key prefixing** - Each backend uses function-specific prefixes/filters
104118
5. **Test isolation fixtures** - Separate cache directories for pickle backend
105119
6. **No naming collisions** - Test authors have been careful to use unique function names
106120

107-
This design allows tests to run in parallel without interfering with each other, as each test operates on its own namespace within the cache backends.
121+
This design allows tests to run in parallel without interfering with each other, as each test operates on its own namespace within the cache backends.

tests/README.md

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -136,21 +136,23 @@ pytest -n 4
136136
import pytest
137137
from cachier import cachier
138138

139+
139140
def test_basic_caching():
140141
"""Test basic caching functionality."""
142+
141143
# Define a cached function local to this test
142144
@cachier()
143145
def expensive_computation(x):
144-
return x ** 2
145-
146+
return x**2
147+
146148
# First call - should compute
147149
result1 = expensive_computation(5)
148150
assert result1 == 25
149-
151+
150152
# Second call - should return from cache
151153
result2 = expensive_computation(5)
152154
assert result2 == 25
153-
155+
154156
# Clear cache for cleanup
155157
expensive_computation.clear_cache()
156158
```
@@ -162,11 +164,11 @@ def test_basic_caching():
162164
def test_mongo_specific_feature():
163165
"""Test MongoDB-specific functionality."""
164166
from tests.test_mongo_core import _test_mongetter
165-
167+
166168
@cachier(mongetter=_test_mongetter)
167169
def mongo_cached_func(x):
168170
return x * 2
169-
171+
170172
# Test implementation
171173
assert mongo_cached_func(5) == 10
172174
```
@@ -180,6 +182,7 @@ def test_mongo_specific_feature():
180182
#### Why This Matters
181183

182184
Cachier identifies cached functions by their full module path and function name. When tests share decorated functions:
185+
183186
- Cache entries can conflict between tests
184187
- Parallel test execution may fail unpredictably
185188
- Test results become non-deterministic
@@ -191,14 +194,15 @@ def test_feature_one():
191194
@cachier()
192195
def compute_one(x): # Unique to this test
193196
return x * 2
194-
197+
195198
assert compute_one(5) == 10
196199

200+
197201
def test_feature_two():
198202
@cachier()
199203
def compute_two(x): # Different function for different test
200204
return x * 2
201-
205+
202206
assert compute_two(5) == 10
203207
```
204208

@@ -210,9 +214,11 @@ def test_feature_two():
210214
def shared_compute(x): # Shared between tests
211215
return x * 2
212216

217+
213218
def test_feature_one():
214219
assert shared_compute(5) == 10 # May conflict with test_feature_two
215220

221+
216222
def test_feature_two():
217223
assert shared_compute(5) == 10 # May conflict with test_feature_one
218224
```
@@ -239,10 +245,11 @@ def test_feature_two():
239245
@pytest.mark.mongo
240246
def test_mongo_feature():
241247
"""Test with MongoDB backend."""
248+
242249
@cachier(mongetter=_test_mongetter, wait_for_calc_timeout=2)
243250
def mongo_func(x):
244251
return x
245-
252+
246253
# MongoDB-specific assertions
247254
assert mongo_func.get_cache_mongetter() is not None
248255
```
@@ -253,10 +260,11 @@ def test_mongo_feature():
253260
@pytest.mark.redis
254261
def test_redis_feature():
255262
"""Test with Redis backend."""
256-
@cachier(backend='redis', redis_client=_test_redis_client)
263+
264+
@cachier(backend="redis", redis_client=_test_redis_client)
257265
def redis_func(x):
258266
return x
259-
267+
260268
# Redis-specific testing
261269
assert redis_func(5) == 5
262270
```
@@ -267,10 +275,11 @@ def test_redis_feature():
267275
@pytest.mark.sql
268276
def test_sql_feature():
269277
"""Test with SQL backend."""
270-
@cachier(backend='sql', sql_engine=test_engine)
278+
279+
@cachier(backend="sql", sql_engine=test_engine)
271280
def sql_func(x):
272281
return x
273-
282+
274283
# SQL-specific testing
275284
assert sql_func(5) == 5
276285
```
@@ -281,10 +290,11 @@ def test_sql_feature():
281290
@pytest.mark.memory
282291
def test_memory_feature():
283292
"""Test with memory backend."""
284-
@cachier(backend='memory')
293+
294+
@cachier(backend="memory")
285295
def memory_func(x):
286296
return x
287-
297+
288298
# Memory-specific testing
289299
assert memory_func(5) == 5
290300
```
@@ -345,50 +355,61 @@ pytest -m sql
345355
### Common Issues
346356

347357
1. **Import Errors**: Install backend-specific requirements
358+
348359
```bash
349360
pip install -r tests/redis_requirements.txt
350361
```
351362

352363
2. **Docker Not Running**: Start Docker Desktop or daemon
364+
353365
```bash
354366
docker ps # Check if Docker is running
355367
```
356368

357369
3. **Port Conflicts**: Stop conflicting services
370+
358371
```bash
359372
docker stop cachier-test-mongo cachier-test-redis cachier-test-postgres
360373
```
361374

362375
4. **Flaky Tests**: Usually due to timing issues
376+
363377
- Increase timeouts
364378
- Add proper waits
365379
- Check for race conditions
366380

367381
5. **Cache Conflicts**: Ensure function isolation
382+
368383
- Don't share decorated functions
369384
- Clear cache after tests
370385
- Use unique function names
371386

372387
### Debugging Tips
373388

374-
1. **Run Single Test**:
389+
1. **Run Single Test**:
390+
375391
```bash
376392
pytest -k test_name -v
377393
```
378394

379-
2. **Disable Parallel**:
395+
2. **Disable Parallel**:
396+
380397
```bash
381398
pytest -n 1
382399
```
383400

384401
3. **Check Logs**:
402+
385403
```bash
386404
docker logs cachier-test-mongo
387405
```
388406

389407
4. **Interactive Debugging**:
408+
390409
```python
391-
import pdb; pdb.set_trace()
410+
import pdb
411+
412+
pdb.set_trace()
392413
```
393414

394415
### Performance Considerations
@@ -427,4 +448,4 @@ When adding new tests:
427448
- Check existing tests for examples
428449
- Review the main README.rst
429450
- Open an issue on GitHub
430-
- Contact maintainers listed in README.rst
451+
- Contact maintainers listed in README.rst

0 commit comments

Comments
 (0)