Skip to content

Commit 30f4b03

Browse files
committed
Merge branch 'mdmosby-fix-dup-ids'
2 parents b26d0d2 + 5de85f8 commit 30f4b03

1 file changed

Lines changed: 44 additions & 25 deletions

File tree

src/_canary/testspec.py

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ def unmasked(cls) -> "Mask":
6161
@dataclasses.dataclass
6262
class BaseSpec(Generic[T]):
6363
file_root: Path
64+
"""The search path contiaining the generated spec; typically the some version-control root"""
6465
file_path: Path
66+
"""The path to the test file relative to `file_root`"""
6567
family: str = ""
6668
stdout: str = "canary-out.txt"
6769
stderr: str | None = None # combine stdout/stderr by default
@@ -132,6 +134,7 @@ def from_dict(cls: Type[T], d: dict, lookup: dict[str, T]) -> T:
132134

133135
@cached_property
134136
def file(self) -> Path:
137+
"""Path to the test specification file"""
135138
return self.file_root / self.file_path
136139

137140
@property
@@ -485,40 +488,56 @@ def _generate_dependency_patterns(
485488

486489

487490
class _GlobalSpecCache:
488-
_file_hash: dict[Path, str] = {}
489-
_repo_root: dict[Path, Path] = {}
490-
_lock = threading.Lock()
491+
"""Simple cache for storing re-used data feeding the spec ID"""
491492

492-
@classmethod
493-
def file_hash(cls, path: Path) -> str:
494-
path = path.absolute()
495-
try:
496-
return cls._file_hash[path]
497-
except KeyError:
498-
pass
499-
h = hashlib.blake2b(digest_size=16)
500-
h.update(path.read_bytes())
501-
digest = h.hexdigest()
502-
with cls._lock:
503-
return cls._file_hash.setdefault(path, digest)
493+
_key: dict[Path, Path] = {}
494+
"""Maps the input file path to a key index (absolute path)"""
495+
496+
_file_hash: dict[Path, bytes] = {}
497+
_repo_root: dict[Path, bytes] = {}
498+
_rel_repo: dict[Path, bytes] = {}
499+
_lock = threading.Lock()
504500

505501
@classmethod
506-
def repo_root(cls, path: Path) -> Path:
507-
path = path.absolute()
508-
try:
509-
return cls._repo_root[path]
510-
except KeyError:
511-
pass
502+
def _compute_repo_root(cls, path: Path) -> Path:
512503
d = path.parent
513504
while d.parent != d:
514505
if (d / ".git").exists() or (d / ".repo").exists():
515506
root = d
516507
break
517508
d = d.parent
518509
else:
519-
root = path.parent
510+
root = d
511+
return root
512+
513+
@classmethod
514+
def populate_cache(cls, path: Path) -> Path:
515+
try:
516+
return cls._key[path]
517+
except KeyError:
518+
pass
519+
520+
key = path.absolute()
521+
h = hashlib.blake2b(digest_size=16)
522+
h.update(key.read_bytes())
523+
root = cls._compute_repo_root(key)
524+
rel = key.relative_to(root)
525+
520526
with cls._lock:
521-
return cls._repo_root.setdefault(path, root)
527+
cls._repo_root[key] = str(root).encode()
528+
cls._rel_repo[key] = str(rel).encode()
529+
cls._file_hash[key] = h.hexdigest().encode()
530+
return cls._key.setdefault(path, key)
531+
532+
@classmethod
533+
def file_hash(cls, path: Path) -> bytes:
534+
key = cls.populate_cache(path)
535+
return cls._file_hash[key]
536+
537+
@classmethod
538+
def rel_repo(cls, path: Path) -> bytes:
539+
key = cls.populate_cache(path)
540+
return cls._rel_repo[key]
522541

523542

524543
def build_spec_id(spec: BaseSpec) -> str:
@@ -529,8 +548,8 @@ def build_spec_id(spec: BaseSpec) -> str:
529548
if parameters:
530549
for p in sorted(parameters):
531550
hasher.update(f"{p}={stringify(parameters[p], float_fmt='%.16e')}".encode())
532-
hasher.update(_GlobalSpecCache.file_hash(spec.file).encode())
533-
hasher.update(str(_GlobalSpecCache.repo_root(spec.file)).encode())
551+
hasher.update(_GlobalSpecCache.file_hash(spec.file))
552+
hasher.update(_GlobalSpecCache.rel_repo(spec.file))
534553
return hasher.hexdigest()
535554

536555

0 commit comments

Comments
 (0)