every libs/*.py and hooks/*.py now starts with a one-line module docstring; every bin/* script starts with a `# purpose:` header. discovery-by-`ls`-and-read instead of by index. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
40 lines
829 B
Python
40 lines
829 B
Python
"""hashable: dict/set subclasses with stable __hash__ via canonical JSON — lets you nest dicts/sets inside sets in metadata."""
|
|
|
|
import json
|
|
from functools import total_ordering
|
|
|
|
from bundlewrap.metadata import MetadataJSONEncoder
|
|
|
|
|
|
@total_ordering
|
|
class Hashable():
|
|
def _json(self):
|
|
return json.dumps(
|
|
self,
|
|
sort_keys=True,
|
|
cls=MetadataJSONEncoder,
|
|
)
|
|
|
|
def __lt__(self, other):
|
|
return self._json() < other._json()
|
|
|
|
def __eq__(self, other):
|
|
return self._json() == other._json()
|
|
|
|
def __hash__(self):
|
|
return hash(self._json())
|
|
|
|
|
|
class HashableDict(Hashable, dict):
|
|
pass
|
|
|
|
|
|
class HashableSet(Hashable, set):
|
|
pass
|
|
|
|
|
|
def hashable(object):
|
|
return {
|
|
dict: HashableDict,
|
|
set: HashableSet,
|
|
}[type(object)](object)
|