vcti-cache 1.1.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.
@@ -0,0 +1,8 @@
1
+ Copyright (c) 2018-2026 Visual Collaboration Technologies Inc.
2
+ All Rights Reserved.
3
+
4
+ This software is proprietary and confidential. Unauthorized copying,
5
+ distribution, or use of this software, via any medium, is strictly
6
+ prohibited. Access is granted only to authorized VCollab developers
7
+ and individuals explicitly authorized by Visual Collaboration
8
+ Technologies Inc.
@@ -0,0 +1,192 @@
1
+ Metadata-Version: 2.4
2
+ Name: vcti-cache
3
+ Version: 1.1.1
4
+ Summary: VCollab Cache - size-bounded object cache with pluggable eviction policies
5
+ Author: Visual Collaboration Technologies Inc.
6
+ Requires-Python: <3.15,>=3.12
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Provides-Extra: test
10
+ Requires-Dist: pytest; extra == "test"
11
+ Requires-Dist: pytest-cov; extra == "test"
12
+ Provides-Extra: lint
13
+ Requires-Dist: ruff; extra == "lint"
14
+ Dynamic: license-file
15
+
16
+ # Object Cache
17
+
18
+ ## Purpose
19
+
20
+ VCollab applications frequently need to hold computed or loaded objects
21
+ in memory with a bounded size budget. When the budget is exceeded, old
22
+ entries must be evicted according to a configurable policy.
23
+
24
+ The `vcti-cache` package provides `ObjectCache`, a generic,
25
+ size-bounded cache with a pluggable eviction policy defined by the
26
+ abstract `CachePolicy` base class. Implement `CachePolicy` to control
27
+ how item sizes are calculated and which items are evicted first.
28
+
29
+ This package has **zero external dependencies**.
30
+
31
+ ---
32
+
33
+ ## Installation
34
+
35
+ ### From GitHub (recommended for development)
36
+
37
+ ```bash
38
+ # Latest main branch
39
+ pip install vcti-cache
40
+
41
+
42
+ ### From a GitHub Release
43
+
44
+ Download the wheel from the
45
+ [Releases](https://github.com/vcollab/vcti-python-cache/releases)
46
+ page and install directly:
47
+
48
+ ```bash
49
+ pip install vcti-cache>=1.1.1
50
+ ```
51
+
52
+ ### In `requirements.txt`
53
+
54
+ ```
55
+ vcti-cache>=1.1.1
56
+ ```
57
+
58
+ ### In `pyproject.toml` dependencies
59
+
60
+ ```toml
61
+ dependencies = [
62
+ "vcti-cache>=1.1.1",
63
+ ]
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Quick Start
69
+
70
+ ```python
71
+ from vcti.cache import ObjectCache, LruPolicy
72
+
73
+ # 1. Create a cache with a built-in LRU policy
74
+ cache = ObjectCache[str](max_size=100, cache_policy=LruPolicy(get_size=len))
75
+
76
+ # 2. Add, retrieve, and remove items
77
+ cache.add("greeting", "hello")
78
+ print(cache.get("greeting")) # "hello"
79
+ print(cache["greeting"]) # "hello" (bracket syntax)
80
+ print("greeting" in cache) # True
81
+ print(len(cache)) # 1
82
+ print(cache.current_size) # 5
83
+
84
+ # 3. Update (upsert) an existing item
85
+ cache.update("greeting", "hi there")
86
+ print(cache.get("greeting")) # "hi there"
87
+
88
+ # 4. Inspect statistics
89
+ print(cache.stats.hits) # 2 (from the get + bracket access)
90
+ print(cache.stats.adds) # 2 (original add + update)
91
+
92
+ cache.remove("greeting")
93
+ print(cache.get("greeting")) # None
94
+ ```
95
+
96
+ Three bundled policies are available — `FifoPolicy`, `LruPolicy`,
97
+ `LfuPolicy` — each accepting a `get_size` callable. For custom
98
+ eviction logic, subclass `CachePolicy[T]` directly (see
99
+ [Extending](docs/extending.md)).
100
+
101
+ ---
102
+
103
+ ## Thread Safety
104
+
105
+ `ObjectCache` is **not thread-safe**. If you share a cache across threads,
106
+ wrap it with an external lock (e.g. `threading.Lock`).
107
+
108
+ ---
109
+
110
+ ## Public API
111
+
112
+ | Symbol | Kind | Description |
113
+ |--------|------|-------------|
114
+ | `ObjectCache[T]` | Class | Size-bounded cache with eviction support |
115
+ | `CachePolicy[T]` | ABC | Abstract base for eviction strategies |
116
+ | `FifoPolicy[T]` | Policy | First-in-first-out eviction |
117
+ | `LruPolicy[T]` | Policy | Least-recently-used eviction |
118
+ | `LfuPolicy[T]` | Policy | Least-frequently-used eviction |
119
+ | `MruPolicy[T]` | Policy | Most-recently-used eviction (scan-resistant) |
120
+ | `RrPolicy[T]` | Policy | Random replacement (Bélády-immune) |
121
+ | `CacheStats` | Dataclass | Immutable hit/miss/eviction/removal statistics |
122
+ | `CacheOverflowError` | Exception | Raised when an item cannot fit |
123
+
124
+ ### `ObjectCache[T]`
125
+
126
+ | Method / Property | Description |
127
+ |-------------------|-------------|
128
+ | `add(key, value)` | Insert an item; evicts if needed, raises on duplicate key |
129
+ | `update(key, value)` | Insert or replace an item (upsert); evicts if needed |
130
+ | `get(key)` | Retrieve by key or `None` |
131
+ | `cache[key]` | Retrieve by key or raise `KeyError` |
132
+ | `remove(key)` | Remove a single item (fires `on_remove`) |
133
+ | `clear()` | Remove all items |
134
+ | `keys()` | List of current keys |
135
+ | `values()` | List of current values |
136
+ | `items()` | List of `(key, value)` pairs |
137
+ | `iter(cache)` | Iterate over keys |
138
+ | `max_size` | Maximum capacity in bytes |
139
+ | `current_size` | Total size of cached items (bytes) |
140
+ | `get_item_size(key)` | Cached size of an item (bytes), or `None` if missing |
141
+ | `stats` | `CacheStats` instance with hit/miss/eviction counters |
142
+ | `policy` | The active `CachePolicy` instance |
143
+ | `key in cache` | Membership test |
144
+ | `len(cache)` | Number of cached items |
145
+
146
+ ### `CachePolicy[T]` (abstract)
147
+
148
+ | Method | Override | Description |
149
+ |--------|----------|-------------|
150
+ | `get_size(item)` | Required | Return item size in bytes (>= 0) |
151
+ | `get_eviction_items(space, items)` | Required | Return keys to evict |
152
+ | `on_add(key, item)` | Optional | Called after an item is added |
153
+ | `on_access(key, item)` | Optional | Called when an item is retrieved |
154
+ | `on_evict(key, item)` | Optional | Called when an item is evicted by the policy |
155
+ | `on_remove(key, item)` | Optional | Called when an item is explicitly removed by the caller |
156
+
157
+ ### `CacheStats`
158
+
159
+ | Field | Description |
160
+ |-------|-------------|
161
+ | `hits` | Successful `get` / `[]` calls |
162
+ | `misses` | `get` calls returning `None` / `[]` raising `KeyError` |
163
+ | `adds` | Successful `add` / `update` insertions |
164
+ | `evictions` | Items removed by the eviction policy |
165
+ | `removals` | Items explicitly removed by `remove()` / `clear()` / `update()` replacement |
166
+
167
+ ### Bundled Policies
168
+
169
+ All bundled policies accept `get_size: Callable[[T], int]` in their
170
+ constructor.
171
+
172
+ | Policy | Eviction Rule | Internal Structure |
173
+ |--------|---------------|--------------------|
174
+ | `FifoPolicy[T]` | Oldest insertion first | `OrderedDict` |
175
+ | `LruPolicy[T]` | Least recently accessed | `OrderedDict` (moves on access) |
176
+ | `LfuPolicy[T]` | Lowest access count (ties: oldest) | `defaultdict(int)` + `OrderedDict` |
177
+ | `MruPolicy[T]` | Most recently accessed | `OrderedDict` (evicts from end) |
178
+ | `RrPolicy[T]` | Random (accepts optional `seed`) | `list` + `random.Random` |
179
+
180
+ **Start with `LruPolicy`** — it's the best general-purpose default.
181
+ See [Choosing a Policy](docs/design.md#choosing-a-policy) for a detailed
182
+ comparison of performance, trade-offs, and when to use each.
183
+
184
+ ---
185
+
186
+ ## Documentation
187
+
188
+ - [Design](docs/design.md) — Architecture, generic type parameter, and policy pattern
189
+ - [Source Guide](docs/source-guide.md) — File-by-file walkthrough
190
+ - [Patterns](docs/patterns.md) — Real-world usage recipes (LRU, statistics, etc.)
191
+ - [Extending](docs/extending.md) — How to write custom eviction policies
192
+ - [API Reference](docs/api.md) — Autodoc for all modules
@@ -0,0 +1,177 @@
1
+ # Object Cache
2
+
3
+ ## Purpose
4
+
5
+ VCollab applications frequently need to hold computed or loaded objects
6
+ in memory with a bounded size budget. When the budget is exceeded, old
7
+ entries must be evicted according to a configurable policy.
8
+
9
+ The `vcti-cache` package provides `ObjectCache`, a generic,
10
+ size-bounded cache with a pluggable eviction policy defined by the
11
+ abstract `CachePolicy` base class. Implement `CachePolicy` to control
12
+ how item sizes are calculated and which items are evicted first.
13
+
14
+ This package has **zero external dependencies**.
15
+
16
+ ---
17
+
18
+ ## Installation
19
+
20
+ ### From GitHub (recommended for development)
21
+
22
+ ```bash
23
+ # Latest main branch
24
+ pip install vcti-cache
25
+
26
+
27
+ ### From a GitHub Release
28
+
29
+ Download the wheel from the
30
+ [Releases](https://github.com/vcollab/vcti-python-cache/releases)
31
+ page and install directly:
32
+
33
+ ```bash
34
+ pip install vcti-cache>=1.1.1
35
+ ```
36
+
37
+ ### In `requirements.txt`
38
+
39
+ ```
40
+ vcti-cache>=1.1.1
41
+ ```
42
+
43
+ ### In `pyproject.toml` dependencies
44
+
45
+ ```toml
46
+ dependencies = [
47
+ "vcti-cache>=1.1.1",
48
+ ]
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Quick Start
54
+
55
+ ```python
56
+ from vcti.cache import ObjectCache, LruPolicy
57
+
58
+ # 1. Create a cache with a built-in LRU policy
59
+ cache = ObjectCache[str](max_size=100, cache_policy=LruPolicy(get_size=len))
60
+
61
+ # 2. Add, retrieve, and remove items
62
+ cache.add("greeting", "hello")
63
+ print(cache.get("greeting")) # "hello"
64
+ print(cache["greeting"]) # "hello" (bracket syntax)
65
+ print("greeting" in cache) # True
66
+ print(len(cache)) # 1
67
+ print(cache.current_size) # 5
68
+
69
+ # 3. Update (upsert) an existing item
70
+ cache.update("greeting", "hi there")
71
+ print(cache.get("greeting")) # "hi there"
72
+
73
+ # 4. Inspect statistics
74
+ print(cache.stats.hits) # 2 (from the get + bracket access)
75
+ print(cache.stats.adds) # 2 (original add + update)
76
+
77
+ cache.remove("greeting")
78
+ print(cache.get("greeting")) # None
79
+ ```
80
+
81
+ Three bundled policies are available — `FifoPolicy`, `LruPolicy`,
82
+ `LfuPolicy` — each accepting a `get_size` callable. For custom
83
+ eviction logic, subclass `CachePolicy[T]` directly (see
84
+ [Extending](docs/extending.md)).
85
+
86
+ ---
87
+
88
+ ## Thread Safety
89
+
90
+ `ObjectCache` is **not thread-safe**. If you share a cache across threads,
91
+ wrap it with an external lock (e.g. `threading.Lock`).
92
+
93
+ ---
94
+
95
+ ## Public API
96
+
97
+ | Symbol | Kind | Description |
98
+ |--------|------|-------------|
99
+ | `ObjectCache[T]` | Class | Size-bounded cache with eviction support |
100
+ | `CachePolicy[T]` | ABC | Abstract base for eviction strategies |
101
+ | `FifoPolicy[T]` | Policy | First-in-first-out eviction |
102
+ | `LruPolicy[T]` | Policy | Least-recently-used eviction |
103
+ | `LfuPolicy[T]` | Policy | Least-frequently-used eviction |
104
+ | `MruPolicy[T]` | Policy | Most-recently-used eviction (scan-resistant) |
105
+ | `RrPolicy[T]` | Policy | Random replacement (Bélády-immune) |
106
+ | `CacheStats` | Dataclass | Immutable hit/miss/eviction/removal statistics |
107
+ | `CacheOverflowError` | Exception | Raised when an item cannot fit |
108
+
109
+ ### `ObjectCache[T]`
110
+
111
+ | Method / Property | Description |
112
+ |-------------------|-------------|
113
+ | `add(key, value)` | Insert an item; evicts if needed, raises on duplicate key |
114
+ | `update(key, value)` | Insert or replace an item (upsert); evicts if needed |
115
+ | `get(key)` | Retrieve by key or `None` |
116
+ | `cache[key]` | Retrieve by key or raise `KeyError` |
117
+ | `remove(key)` | Remove a single item (fires `on_remove`) |
118
+ | `clear()` | Remove all items |
119
+ | `keys()` | List of current keys |
120
+ | `values()` | List of current values |
121
+ | `items()` | List of `(key, value)` pairs |
122
+ | `iter(cache)` | Iterate over keys |
123
+ | `max_size` | Maximum capacity in bytes |
124
+ | `current_size` | Total size of cached items (bytes) |
125
+ | `get_item_size(key)` | Cached size of an item (bytes), or `None` if missing |
126
+ | `stats` | `CacheStats` instance with hit/miss/eviction counters |
127
+ | `policy` | The active `CachePolicy` instance |
128
+ | `key in cache` | Membership test |
129
+ | `len(cache)` | Number of cached items |
130
+
131
+ ### `CachePolicy[T]` (abstract)
132
+
133
+ | Method | Override | Description |
134
+ |--------|----------|-------------|
135
+ | `get_size(item)` | Required | Return item size in bytes (>= 0) |
136
+ | `get_eviction_items(space, items)` | Required | Return keys to evict |
137
+ | `on_add(key, item)` | Optional | Called after an item is added |
138
+ | `on_access(key, item)` | Optional | Called when an item is retrieved |
139
+ | `on_evict(key, item)` | Optional | Called when an item is evicted by the policy |
140
+ | `on_remove(key, item)` | Optional | Called when an item is explicitly removed by the caller |
141
+
142
+ ### `CacheStats`
143
+
144
+ | Field | Description |
145
+ |-------|-------------|
146
+ | `hits` | Successful `get` / `[]` calls |
147
+ | `misses` | `get` calls returning `None` / `[]` raising `KeyError` |
148
+ | `adds` | Successful `add` / `update` insertions |
149
+ | `evictions` | Items removed by the eviction policy |
150
+ | `removals` | Items explicitly removed by `remove()` / `clear()` / `update()` replacement |
151
+
152
+ ### Bundled Policies
153
+
154
+ All bundled policies accept `get_size: Callable[[T], int]` in their
155
+ constructor.
156
+
157
+ | Policy | Eviction Rule | Internal Structure |
158
+ |--------|---------------|--------------------|
159
+ | `FifoPolicy[T]` | Oldest insertion first | `OrderedDict` |
160
+ | `LruPolicy[T]` | Least recently accessed | `OrderedDict` (moves on access) |
161
+ | `LfuPolicy[T]` | Lowest access count (ties: oldest) | `defaultdict(int)` + `OrderedDict` |
162
+ | `MruPolicy[T]` | Most recently accessed | `OrderedDict` (evicts from end) |
163
+ | `RrPolicy[T]` | Random (accepts optional `seed`) | `list` + `random.Random` |
164
+
165
+ **Start with `LruPolicy`** — it's the best general-purpose default.
166
+ See [Choosing a Policy](docs/design.md#choosing-a-policy) for a detailed
167
+ comparison of performance, trade-offs, and when to use each.
168
+
169
+ ---
170
+
171
+ ## Documentation
172
+
173
+ - [Design](docs/design.md) — Architecture, generic type parameter, and policy pattern
174
+ - [Source Guide](docs/source-guide.md) — File-by-file walkthrough
175
+ - [Patterns](docs/patterns.md) — Real-world usage recipes (LRU, statistics, etc.)
176
+ - [Extending](docs/extending.md) — How to write custom eviction policies
177
+ - [API Reference](docs/api.md) — Autodoc for all modules
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "vcti-cache"
7
+ version = "1.1.1"
8
+ description = "VCollab Cache - size-bounded object cache with pluggable eviction policies"
9
+ readme = "README.md"
10
+ authors = [
11
+ {name = "Visual Collaboration Technologies Inc."}
12
+ ]
13
+ requires-python = ">=3.12,<3.15"
14
+ dependencies = []
15
+
16
+ [tool.setuptools.packages.find]
17
+ where = ["src"]
18
+ include = ["vcti.cache", "vcti.cache.*"]
19
+
20
+ [project.optional-dependencies]
21
+ test = ["pytest", "pytest-cov"]
22
+ lint = ["ruff"]
23
+
24
+ [tool.setuptools]
25
+ zip-safe = true
26
+
27
+ [tool.setuptools.package-data]
28
+ "vcti.cache" = ["py.typed"]
29
+
30
+ [tool.pytest.ini_options]
31
+ addopts = "--cov=vcti.cache --cov-report=term-missing --cov-fail-under=95"
32
+
33
+ [tool.ruff]
34
+ target-version = "py312"
35
+ line-length = 99
36
+
37
+ [tool.ruff.lint]
38
+ select = ["E", "F", "W", "I", "UP"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,23 @@
1
+ # Copyright Visual Collaboration Technologies Inc. All Rights Reserved.
2
+ # See LICENSE for details.
3
+ """vcti.cache — size-bounded object cache with pluggable eviction policies."""
4
+
5
+ from importlib.metadata import version
6
+
7
+ from .object_cache import CacheOverflowError, CachePolicy, CacheStats, ObjectCache
8
+ from .policies import FifoPolicy, LfuPolicy, LruPolicy, MruPolicy, RrPolicy
9
+
10
+ __version__ = version("vcti-cache")
11
+
12
+ __all__ = [
13
+ "__version__",
14
+ "CacheOverflowError",
15
+ "CachePolicy",
16
+ "CacheStats",
17
+ "FifoPolicy",
18
+ "LfuPolicy",
19
+ "LruPolicy",
20
+ "MruPolicy",
21
+ "ObjectCache",
22
+ "RrPolicy",
23
+ ]