Skip to content

Tighten restrictions and errors for tag APIs - #3

Merged
puddly merged 1 commit into
devfrom
puddly/clean-up-tags-api
Aug 9, 2026
Merged

Tighten restrictions and errors for tag APIs#3
puddly merged 1 commit into
devfrom
puddly/clean-up-tags-api

Conversation

@puddly

@puddly puddly commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Add an allow_missing kwarg and set it to False by default. Returning None or an empty list of tags is something to opt into, as most use cases should crash when a tag is missing.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes tag lookup APIs stricter across GBL3/GBL4/EBL images by adding an allow_missing keyword argument to get_tags() and defaulting it to False, so missing tags raise instead of silently returning []/None. Tests are updated to opt into missing-tag behavior where appropriate.

Changes:

  • Add allow_missing: bool = False to get_tags() in GBL3/GBL4/EBL and raise KeyError by default when no tags are found.
  • Update tests and internal call sites to pass allow_missing=True where “no tags” is expected/acceptable.
  • Remove find_first_tag() / has_tag() helpers and simplify get_first_tag() implementations to index into get_tags() results.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/test_rare_tags.py Updates a missing-tag assertion to use get_tags(..., allow_missing=True) returning [].
tests/test_gbl4.py Updates unknown-tag checks and padding iteration to opt into missing-tag behavior.
tests/test_gbl.py Updates lookup helper expectations and adds coverage for strict KeyError behavior on missing tags (GBL3).
tests/test_elf.py Updates bootloader/metadata presence checks to use allow_missing=True.
tests/test_crypto.py Updates signature absence assertion to use get_tags(..., allow_missing=True) returning [].
tests/test_compression.py Updates “tag removed” assertions to opt into missing-tag behavior.
tests/test_commander_cli.py Updates “skip if no LZMA tags” logic and list comprehensions to use allow_missing=True where appropriate.
pygbl/gbl4.py Changes GBL4Image.get_tags() to be strict by default and removes find_first_tag()/has_tag().
pygbl/gbl3.py Changes GBL3Image.get_tags() to be strict by default and updates internal helpers to use allow_missing=True where needed.
pygbl/ebl.py Changes EBLImage.get_tags() to be strict by default and removes find_first_tag()/has_tag().
Suppressed comments (1)

pygbl/ebl.py:295

  • EBLImage.get_tags() now has a new strict-by-default behavior and an allow_missing opt-in, but there are no tests exercising either the KeyError default or the allow_missing=True path for EBL images. Adding a small unit test in tests/test_ebl.py would help prevent regressions in this API change.
    def get_tags(self, tag_type: type[T], *, allow_missing: bool = False) -> list[T]:
        tags: list[T] = [t for t in self.tags if type(t) is tag_type]

        if not tags and not allow_missing:
            raise KeyError(f"No {tag_type.__name__} tag exists")

        return tags

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pygbl/gbl3.py
Comment on lines +732 to +741
def get_tags(self, tag_type: type[T], *, allow_missing: bool = False) -> list[T]:
tags: list[T] = [t for t in self.tags if type(t) is tag_type]

def find_first_tag(self, tag_type: type[T]) -> T | None:
return next((t for t in self.tags if type(t) is tag_type), None)

def get_first_tag(self, tag_type: type[T]) -> T:
tag = self.find_first_tag(tag_type)

if tag is None:
if not tags and not allow_missing:
raise KeyError(f"No {tag_type.__name__} tag exists")

return tag
return tags

def has_tag(self, tag_type: type[Any]) -> bool:
return self.find_first_tag(tag_type) is not None
def get_first_tag(self, tag_type: type[T]) -> T:
return self.get_tags(tag_type)[0]
Comment thread pygbl/ebl.py
Comment on lines +289 to +298
def get_tags(self, tag_type: type[T], *, allow_missing: bool = False) -> list[T]:
tags: list[T] = [t for t in self.tags if type(t) is tag_type]

def find_first_tag(self, tag_type: type[T]) -> T | None:
return next((t for t in self.tags if type(t) is tag_type), None)

def get_first_tag(self, tag_type: type[T]) -> T:
tag = self.find_first_tag(tag_type)

if tag is None:
if not tags and not allow_missing:
raise KeyError(f"No {tag_type.__name__} tag exists")

return tag
return tags

def has_tag(self, tag_type: type[Any]) -> bool:
return self.find_first_tag(tag_type) is not None
def get_first_tag(self, tag_type: type[T]) -> T:
return self.get_tags(tag_type)[0]
Comment thread pygbl/gbl4.py
Comment on lines 537 to +557
@@ -548,20 +548,10 @@ def walk(tags: list[GBL4TagBase]) -> None:

walk([self.root])

return found

def find_first_tag(self, tag_type: type[T]) -> T | None:
tags = self.get_tags(tag_type)

return tags[0] if tags else None

def get_first_tag(self, tag_type: type[T]) -> T:
tag = self.find_first_tag(tag_type)

if tag is None:
if not found and not allow_missing:
raise KeyError(f"No {tag_type.__name__} tag exists")

return tag
return found

def has_tag(self, tag_type: type[Any]) -> bool:
return self.find_first_tag(tag_type) is not None
def get_first_tag(self, tag_type: type[T]) -> T:
return self.get_tags(tag_type)[0]
Comment thread tests/test_gbl4.py
Comment on lines 64 to +66
def test_no_unknown_tags(path: pathlib.Path) -> None:
"""Every tag in a real image should be one we model."""
assert load(path).get_tags(GBL4UnknownTag) == []
assert load(path).get_tags(GBL4UnknownTag, allow_missing=True) == []
@puddly
puddly merged commit 70c4e59 into dev Aug 9, 2026
21 checks passed
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.

2 participants