rust-py-cache 0.1.1__cp310-abi3-win_amd64.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.
@@ -0,0 +1,22 @@
1
+ """rust-py-cache — An ultra-fast local cache for Python, powered by Rust."""
2
+
3
+ # O módulo nativo (_rust_py_cache) é compilado pelo Rust/maturin e fica DENTRO
4
+ # deste pacote. O core (set/get/delete/exists/keys/stats/cleanup_expired) vem do
5
+ # Rust; aqui só adicionamos açúcar Python — o decorator `cached` — via subclasse.
6
+ from ._rust_py_cache import Cache as _RustCache, hello
7
+ from .decorators import cached as _cached
8
+
9
+
10
+ class Cache(_RustCache):
11
+ """Cache local em memória (core em Rust) + decorator `cached` em Python.
12
+
13
+ Herda todos os métodos do core nativo e adiciona `@cache.cached(...)`. A
14
+ herança só é possível porque o `#[pyclass(subclass)]` libera o tipo nativo
15
+ para ser estendido no Python.
16
+ """
17
+
18
+ cached = _cached
19
+
20
+
21
+ __all__ = ["Cache", "hello"]
22
+ __version__ = "0.1.1"
Binary file
@@ -0,0 +1,64 @@
1
+ """Decorator de memoização — Etapa 17.
2
+
3
+ Fornece `Cache.cached`, um decorator que guarda o retorno de uma função no cache.
4
+ Fica em Python (não no core Rust) porque mexe com `*args/**kwargs`, geração de
5
+ chave e `functools.wraps` — tudo muito mais natural aqui.
6
+ """
7
+
8
+ import functools
9
+
10
+ # Sentinela para distinguir "ausente no cache" de "valor None legítimo".
11
+ # `cache.get(key, _MISSING)` devolve `_MISSING` só quando a chave não existe.
12
+ _MISSING = object()
13
+
14
+
15
+ def _default_key(func, args, kwargs):
16
+ """Chave determinística a partir da função e dos argumentos.
17
+
18
+ Usa `repr` dos argumentos — simples e legível. Pressupõe argumentos
19
+ repr-áveis e estáveis (o caso comum: números, strings, tuplas). Para casos
20
+ exóticos, o usuário pode passar `key=...` explícito.
21
+ """
22
+ parts = [func.__module__ or "", func.__qualname__, repr(args)]
23
+ if kwargs:
24
+ parts.append(repr(sorted(kwargs.items())))
25
+ return "|".join(parts)
26
+
27
+
28
+ def cached(self, ttl=None, key=None):
29
+ """Decorator: memoiza o retorno da função neste cache.
30
+
31
+ Parâmetros:
32
+ ttl: validade em segundos (igual a `set`); `None` = sem expiração.
33
+ key: opcional. String fixa, ou callable `key(*args, **kwargs) -> str`.
34
+ Se omitido, a chave é derivada de função + argumentos.
35
+
36
+ Uso:
37
+ @cache.cached(ttl=60)
38
+ def soma(a, b):
39
+ return a + b
40
+ """
41
+
42
+ def decorator(func):
43
+ @functools.wraps(func)
44
+ def wrapper(*args, **kwargs):
45
+ if key is None:
46
+ cache_key = _default_key(func, args, kwargs)
47
+ elif callable(key):
48
+ cache_key = key(*args, **kwargs)
49
+ else:
50
+ cache_key = key
51
+
52
+ hit = self.get(cache_key, _MISSING)
53
+ if hit is not _MISSING:
54
+ return hit
55
+
56
+ result = func(*args, **kwargs)
57
+ self.set(cache_key, result, ttl=ttl)
58
+ return result
59
+
60
+ # Expõe a chave-base para inspeção/invalidação manual em testes.
61
+ wrapper.__wrapped__ = func
62
+ return wrapper
63
+
64
+ return decorator
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.4
2
+ Name: rust-py-cache
3
+ Version: 0.1.1
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: 3
6
+ Classifier: Programming Language :: Python :: Implementation :: CPython
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
9
+ Classifier: Topic :: Database
10
+ Classifier: Topic :: System :: Distributed Computing
11
+ Summary: An ultra-fast local cache for Python, powered by Rust.
12
+ Keywords: cache,rust,pyo3,ttl,performance
13
+ Author-email: Roberto Lima <robertolima.izphera@gmail.com>
14
+ License: MIT
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
17
+ Project-URL: Homepage, https://github.com/robertolima/rust-py-cache
18
+
19
+ # rust-py-cache
20
+
21
+ > **An ultra-fast local cache for Python, powered by Rust.**
22
+
23
+ A local, in-memory, thread-safe cache with TTL, lazy expiration, and metrics. The
24
+ core is written in Rust (PyO3 + maturin) on top of a concurrent `DashMap`; the
25
+ Python API is minimal. Think of it as a "mini Redis" living **inside** your Python
26
+ process.
27
+
28
+ [![PyPI](https://img.shields.io/pypi/v/rust-py-cache)](https://pypi.org/project/rust-py-cache/)
29
+ [![Python](https://img.shields.io/pypi/pyversions/rust-py-cache)](https://pypi.org/project/rust-py-cache/)
30
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow)](./LICENSE)
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install rust-py-cache
36
+ ```
37
+
38
+ To work on it locally (requires Rust + maturin):
39
+
40
+ ```bash
41
+ python -m venv .venv && source .venv/bin/activate
42
+ pip install maturin pytest
43
+ maturin develop # compiles the Rust core and installs into the venv
44
+ pytest # runs the tests
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ```python
50
+ from rust_py_cache import Cache
51
+
52
+ cache = Cache()
53
+
54
+ cache.set("user:1", {"name": "Roberto"}, ttl=60) # ttl in seconds
55
+ user = cache.get("user:1") # {"name": "Roberto"}
56
+ cache.get("missing", default=0) # 0
57
+
58
+ cache.exists("user:1") # True (honors TTL)
59
+ cache.delete("user:1") # True if removed, False if absent
60
+ cache.len() # approximate size
61
+ cache.keys() # list of keys
62
+ cache.cleanup_expired() # remove expired entries; returns the count
63
+ cache.clear() # remove everything (keeps counters)
64
+ cache.stats() # {'hits', 'misses', 'sets', 'deletes', 'expired', 'size'}
65
+ ```
66
+
67
+ ### Memoization decorator
68
+
69
+ ```python
70
+ @cache.cached(ttl=60)
71
+ def add(a, b):
72
+ return a + b
73
+
74
+ add(2, 3) # runs and caches
75
+ add(2, 3) # served from cache
76
+
77
+ # custom key (fixed string or callable):
78
+ @cache.cached(ttl=300, key=lambda user_id: f"user:{user_id}")
79
+ def load_user(user_id):
80
+ ...
81
+ ```
82
+
83
+ See full examples under [`examples/`](./examples) (FastAPI and Django).
84
+
85
+ ## API
86
+
87
+ | Method | Description |
88
+ |---|---|
89
+ | `set(key, value, ttl=None)` | Store a value. `ttl` in seconds (`int`/`float`); `None` = no expiration; `ttl <= 0` → `ValueError`. Overwrites. |
90
+ | `get(key, default=None)` | The value, or `default` if missing/expired (expired entries are removed). |
91
+ | `delete(key)` | `True` if removed, `False` if it didn't exist. |
92
+ | `exists(key)` | `True`/`False`, honoring TTL. |
93
+ | `keys()` | List of keys (may include expired-but-not-yet-collected ones). |
94
+ | `len()` / `len(cache)` | Approximate size. |
95
+ | `clear()` | Remove everything (does not reset counters). |
96
+ | `cleanup_expired()` | Remove expired entries; returns how many. |
97
+ | `stats()` | `dict` with `hits, misses, sets, deletes, expired, size`. |
98
+ | `@cache.cached(ttl=None, key=None)` | Memoization decorator. |
99
+
100
+ ## How it works
101
+
102
+ - **Serialization:** in the MVP, values are serialized with `pickle` (on the Python
103
+ side, via PyO3) and stored as opaque bytes (`Vec<u8>`) in the Rust core.
104
+ - **Concurrency:** `DashMap` (a HashMap with per-shard locks) plus `AtomicU64`
105
+ counters, with no global lock on the hot path. Thread-safe, no busy loop.
106
+ - **TTL:** expiration is **lazy** — an expired key is removed when accessed
107
+ (`get`/`exists`) or via `cleanup_expired()`. There is no background thread in the MVP.
108
+
109
+ ## Limitations
110
+
111
+ - The cache is **process-local**: multiple workers = multiple independent caches.
112
+ - It does **not** replace Redis for distributed caching.
113
+ - Data is **lost** when the process restarts.
114
+ - `pickle` must **not** be used to deserialize untrusted data.
115
+ - Lazy TTL: expired items may linger until accessed or until `cleanup_expired()`.
116
+
117
+ ## Development
118
+
119
+ ```bash
120
+ cargo test # Rust core tests
121
+ maturin develop # rebuild and install
122
+ pytest # Python tests
123
+ ```
124
+
125
+ > If `maturin develop` complains about both `VIRTUAL_ENV` and `CONDA_PREFIX` being
126
+ > set, run `conda deactivate` first, or use `env -u CONDA_PREFIX maturin develop`.
127
+
128
+ ## Roadmap
129
+
130
+ Stages and next steps (LRU/LFU eviction, background expiration, configurable
131
+ serializer, namespaces, etc.) are in [ROADMAP.md](./ROADMAP.md).
132
+
133
+ ## License
134
+
135
+ MIT
136
+
@@ -0,0 +1,7 @@
1
+ rust_py_cache/__init__.py,sha256=ik8zJVOuYg8BrHSP2psDcyOJc6vqUyTLfaflD2UQ9l0,834
2
+ rust_py_cache/_rust_py_cache.pyd,sha256=0L6i6vgdBVDi-10ZsIo3cuG7MyrqK6tYCPFekQ6JAvE,331264
3
+ rust_py_cache/decorators.py,sha256=fqH-JQTwSilH-m7te4n9GvPQUZgVoGYZh--ne3_GU_E,2174
4
+ rust_py_cache-0.1.1.dist-info/METADATA,sha256=jHZu9sabDZ6heDUaB-SmAFI1OUACESNJmO65YL1EutA,5028
5
+ rust_py_cache-0.1.1.dist-info/WHEEL,sha256=_qjkWZs5yrFgc7wGyX42BWq6PiACrY0XI82VSrZ_57E,96
6
+ rust_py_cache-0.1.1.dist-info/sboms/rust_py_cache.cyclonedx.json,sha256=W1bqYnXOSg9GnNzf65_nwMPvsJKmgB_iuTANf58XjhA,36745
7
+ rust_py_cache-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.14.1)
3
+ Root-Is-Purelib: false
4
+ Tag: cp310-abi3-win_amd64