Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/specify_cli/extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -641,8 +641,12 @@ def _load(self) -> dict:
if not isinstance(data.get("extensions"), dict):
data["extensions"] = {}
return data
except (json.JSONDecodeError, FileNotFoundError):
# Corrupted or missing registry, start fresh
except (json.JSONDecodeError, UnicodeDecodeError, FileNotFoundError):
Comment thread
marcelsafin marked this conversation as resolved.
# Corrupted or missing registry, start fresh. A registry whose
# bytes cannot be decoded as UTF-8 is the same corruption class
# as malformed JSON — only the exception type differs. OSError is
# deliberately not caught: the data may be intact on disk, and
# starting fresh would let a later _save() wipe it.
return {"schema_version": self.SCHEMA_VERSION, "extensions": {}}

def _save(self):
Expand Down
22 changes: 22 additions & 0 deletions tests/test_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,28 @@ def test_list_returns_empty_dict_for_corrupted_registry(self, temp_dir):
result = registry.list()
assert result == {}

def test_load_starts_fresh_for_non_utf8_registry(self, temp_dir):
"""A registry file with undecodable bytes must start fresh, not raise.

``_load()`` documents "Corrupted or missing registry, start fresh" and
already treats malformed JSON that way, but a registry whose *bytes*
cannot be decoded as UTF-8 raised a raw ``UnicodeDecodeError`` from the
same boundary — the same corruption class reaching a different
exception type.
"""
extensions_dir = temp_dir / "extensions"
extensions_dir.mkdir()
(extensions_dir / ExtensionRegistry.REGISTRY_FILE).write_bytes(
b"\xff\xfe not utf-8 \xc3\x28"
Comment thread
marcelsafin marked this conversation as resolved.
)

registry = ExtensionRegistry(extensions_dir)

assert registry.data == {
"schema_version": ExtensionRegistry.SCHEMA_VERSION,
"extensions": {},
}


# ===== ExtensionManager Tests =====

Expand Down