Skip to content

Replace frozendict (LGPL-3.0) with a stdlib hashable dict in lru_cache#35

Merged
fferflo merged 4 commits into
fferflo:masterfrom
nperraud:drop-frozendict
Jun 5, 2026
Merged

Replace frozendict (LGPL-3.0) with a stdlib hashable dict in lru_cache#35
fferflo merged 4 commits into
fferflo:masterfrom
nperraud:drop-frozendict

Conversation

@nperraud

@nperraud nperraud commented May 28, 2026

Copy link
Copy Markdown
Contributor

Closes #34.

What

  • Remove frozendict from dependencies in pyproject.toml
  • Drop import frozendict from einx/_src/util/lru_cache.py
  • Replace the frozendict.frozendict(...) branch in _freeze_value with a tiny stdlib dict subclass (_FrozenDict) that is hashable

Why this works

_freeze_value produces hashable keys for functools.lru_cache. The frozen value must stay a real mapping, because downstream code reads it back via key access (e.g. kwargs["backend"] in _construct_graph) — so a plain tuple is not enough.

_FrozenDict subclasses dict, so it keeps full mapping behaviour, and defines an order-independent __hash__ (hash(frozenset(self.items()))) so it can be used as an lru_cache key. Since equal dicts hash equally and compare equal, cache-hit behaviour is preserved.

Why this matters

frozendict is released under LGPL-3.0. einx is MIT-licensed and widely used as a transitive dependency (e.g. via x-transformers), so the frozendict dep silently propagates LGPL-3.0 into downstream projects that otherwise use only permissive licenses. This change removes that last LGPL-3.0 dep with a stdlib-only replacement.

Notes

  • An earlier revision of this PR replaced the frozen dict with a plain tuple. That broke the test suite (TypeError: tuple indices must be integers or slices, not str) because the frozen value is read back as a mapping downstream. The _FrozenDict approach fixes this while keeping the no-frozendict goal.
  • Added a CHANGELOG entry.

nperraud and others added 4 commits May 28, 2026 12:18
Fixes the LGPL-3.0 license propagation reported in issue fferflo#34.
frozendict was used solely to make dict args hashable as lru_cache
keys. A tuple of (key, frozen_value) pairs is equally hashable and
correct, requires no third-party dep, and preserves cache-hit
semantics since Python 3.7+ guarantees dict insertion order.
The previous tuple replacement broke downstream code that reads frozen
kwargs back via key access (e.g. kwargs["backend"] in _construct_graph),
causing 'TypeError: tuple indices must be integers or slices, not str'.

Use a minimal stdlib dict subclass with an order-independent __hash__ so
the frozen value stays a real mapping while remaining hashable for
functools.lru_cache. Still no frozendict dependency.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@nperraud nperraud changed the title Replace frozendict (LGPL-3.0) with stdlib tuple in lru_cache Replace frozendict (LGPL-3.0) with a stdlib hashable dict in lru_cache Jun 3, 2026
@fferflo fferflo merged commit 70f9541 into fferflo:master Jun 5, 2026
4 checks passed
@fferflo

fferflo commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Looks good, thanks for the contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace frozendict dependency (LGPL-3.0) with a stdlib-only alternative in lru_cache

3 participants