pycasher 0.2.0__tar.gz → 0.2.2__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 (40) hide show
  1. {pycasher-0.2.0 → pycasher-0.2.2}/PKG-INFO +1 -1
  2. {pycasher-0.2.0 → pycasher-0.2.2}/pyproject.toml +1 -1
  3. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/config.py +3 -1
  4. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/serializer.py +1 -1
  5. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_config.py +12 -5
  6. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_serializer.py +23 -0
  7. {pycasher-0.2.0 → pycasher-0.2.2}/uv.lock +1 -1
  8. {pycasher-0.2.0 → pycasher-0.2.2}/.gitignore +0 -0
  9. {pycasher-0.2.0 → pycasher-0.2.2}/LICENSE +0 -0
  10. {pycasher-0.2.0 → pycasher-0.2.2}/README.md +0 -0
  11. {pycasher-0.2.0 → pycasher-0.2.2}/documentation/00-Introduction.md +0 -0
  12. {pycasher-0.2.0 → pycasher-0.2.2}/documentation/10-Quick-Start.md +0 -0
  13. {pycasher-0.2.0 → pycasher-0.2.2}/documentation/20-API-Reference.md +0 -0
  14. {pycasher-0.2.0 → pycasher-0.2.2}/documentation/_last-updated_.txt +0 -0
  15. {pycasher-0.2.0 → pycasher-0.2.2}/idea.txt +0 -0
  16. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/__init__.py +0 -0
  17. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/_runner.py +0 -0
  18. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/acache.py +0 -0
  19. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/audit_hook.py +0 -0
  20. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/auto_cli.py +0 -0
  21. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/capture.py +0 -0
  22. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/decorator.py +0 -0
  23. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/deps.py +0 -0
  24. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/eviction.py +0 -0
  25. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/hasher.py +0 -0
  26. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/store.py +0 -0
  27. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/strace.py +0 -0
  28. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/__init__.py +0 -0
  29. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/config.py +0 -0
  30. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_acache.py +0 -0
  31. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_audit_hook.py +0 -0
  32. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_auto_cli.py +0 -0
  33. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_capture.py +0 -0
  34. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_decorator.py +0 -0
  35. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_deps.py +0 -0
  36. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_eviction.py +0 -0
  37. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_hasher.py +0 -0
  38. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_store.py +0 -0
  39. {pycasher-0.2.0 → pycasher-0.2.2}/src/casher/tests/test_strace.py +0 -0
  40. {pycasher-0.2.0 → pycasher-0.2.2}/upload_pypi.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycasher
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Cache function results and side effects (stdout, stderr, file writes) with automatic file I/O discovery via strace or audit hooks
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pycasher"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "Cache function results and side effects (stdout, stderr, file writes) with automatic file I/O discovery via strace or audit hooks"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -22,7 +22,9 @@ def configure(
22
22
  """Set runtime config. Takes priority over env vars and defaults.
23
23
  Call before any @cached function. Pass None to clear an override."""
24
24
  if cache_dir is not None:
25
- _overrides["cache_dir"] = Path(cache_dir)
25
+ p = Path(cache_dir)
26
+ p.mkdir(parents=True, exist_ok=True)
27
+ _overrides["cache_dir"] = p
26
28
  elif "cache_dir" in _overrides:
27
29
  del _overrides["cache_dir"]
28
30
 
@@ -51,7 +51,7 @@ def _hash_into(h: "hashlib._Hash", val: Any) -> None:
51
51
  for item in sorted(val, key=repr):
52
52
  _hash_into(h, item)
53
53
  elif isinstance(val, Path):
54
- if val.exists():
54
+ if val.is_file():
55
55
  h.update(val.read_bytes())
56
56
  else:
57
57
  h.update(repr(val).encode())
@@ -15,18 +15,25 @@ def test_configure_cache_dir(tmp_path):
15
15
  assert resolve_cache_dir(None) == tmp_path / "custom"
16
16
 
17
17
 
18
+ def test_configure_creates_nested_dirs(tmp_path):
19
+ nested = tmp_path / "a" / "b" / "c" / "cache"
20
+ assert not nested.exists()
21
+ configure(cache_dir=nested)
22
+ assert nested.is_dir()
23
+
24
+
18
25
  def test_configure_max_cache_bytes():
19
26
  configure(max_cache_bytes=999)
20
27
  assert resolve_max_cache_bytes(None) == 999
21
28
 
22
29
 
23
- def test_configure_clears_on_none():
24
- configure(cache_dir="/some/path")
25
- assert str(resolve_cache_dir(None)) == "/some/path"
30
+ def test_configure_clears_on_none(tmp_path):
31
+ configure(cache_dir=tmp_path / "some_path")
32
+ assert resolve_cache_dir(None) == tmp_path / "some_path"
26
33
  # Calling configure without cache_dir clears the override
27
34
  configure(cache_dir=None)
28
- # Falls back to env or default — just check it's no longer /some/path
29
- assert str(resolve_cache_dir(None)) != "/some/path"
35
+ # Falls back to env or default — just check it's no longer our path
36
+ assert resolve_cache_dir(None) != tmp_path / "some_path"
30
37
 
31
38
 
32
39
  def test_explicit_arg_beats_configure(tmp_path):
@@ -90,3 +90,26 @@ def test_roundtrip_pandas_df(tmp_path):
90
90
  meta = serialize_value(df, tmp_path)
91
91
  restored = deserialize_value(meta, tmp_path)
92
92
  pd.testing.assert_frame_equal(df, restored)
93
+
94
+
95
+ @pytest.mark.timeout(10)
96
+ def test_hash_path_directory(tmp_path):
97
+ """hash_value on a directory Path must not crash (no read_bytes on dirs)."""
98
+ d = tmp_path / "subdir"
99
+ d.mkdir()
100
+ # Should not raise IsADirectoryError
101
+ h = hash_value(d)
102
+ assert isinstance(h, bytes)
103
+ assert len(h) > 0
104
+ # Deterministic
105
+ assert hash_value(d) == hash_value(d)
106
+
107
+
108
+ @pytest.mark.timeout(10)
109
+ def test_hash_path_file_vs_dir(tmp_path):
110
+ """File Path hashes content; directory Path hashes repr — they differ."""
111
+ f = tmp_path / "file.txt"
112
+ f.write_text("hello")
113
+ d = tmp_path / "dir"
114
+ d.mkdir()
115
+ assert hash_value(f) != hash_value(d)
@@ -575,7 +575,7 @@ wheels = [
575
575
 
576
576
  [[package]]
577
577
  name = "pycasher"
578
- version = "0.2.0"
578
+ version = "0.2.2"
579
579
  source = { editable = "." }
580
580
  dependencies = [
581
581
  { name = "loguru" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes