Skip to content

query: fix missing operator attribute on Query objects - #67

Merged
gentoo-bot merged 3 commits into
gentoo:masterfrom
mattst88:bug981521
Aug 29, 2026
Merged

query: fix missing operator attribute on Query objects#67
gentoo-bot merged 3 commits into
gentoo:masterfrom
mattst88:bug981521

Conversation

@mattst88

Copy link
Copy Markdown
Contributor

portage.dep.Atom now uses __slots__ and exposes operator as a read-only @property backed by _operator, so it no longer appears in atom.__dict__. Query.__init__ copies atom.__dict__ into self but never picked up operator, same gap already patched here for cpv, _version, and _cp. Dependencies (a Query subclass) then lacked .operator entirely, crashing equery d with AttributeError when Atom.intersects() compared against it.

Bug: https://bugs.gentoo.org/981521

@thesamesam thesamesam left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I look forward to when we can clean a lot of this up!

portage.dep.Atom now uses __slots__ and exposes operator as a read-only
@Property backed by _operator, so it no longer appears in atom.__dict__.
Query.__init__ copies atom.__dict__ into self but never picked up
operator, same gap already patched here for cpv, _version, and _cp.
Dependencies (a Query subclass) then lacked .operator entirely, crashing
equery d with AttributeError when Atom.intersects() compared against it.

Bug: https://bugs.gentoo.org/981521
Signed-off-by: Matt Turner <mattst88@gentoo.org>
Atom.intersects() type-checks its argument since portage removed str
subtyping from Atom, so it needs a real Atom object, not a Dependencies
(a Query subclass) or a plain string.

graph_reverse_depends() called dep.intersects(self) where self is a
Dependencies object. Pass self.atom instead, but that then exposed a
second bug: gentoolkit.atom.Atom.__init__ sets self.atom to the raw atom
string it was constructed from (used by __repr__/__str__).
Query.__init__ copied that string into self.atom via __dict__.update(),
and its fallback except branch set self.atom = self.cpv (also a plain
string), so Query.atom was never actually usable as an Atom. Fix both:
restore self.atom to the real Atom object in the success path, and
construct one from self.cpv in the fallback path.

That still leaves bare package-name queries (e.g. "simdjson") crashing:
they parse as neither a valid atom nor a valid CPV, so Query.__init__
falls back further to a plain string in self.atom, which
Atom.intersects() can't type-check. Since gentoolkit's Atom can't
represent a name-only atom at all (portage.dep.Atom rejects it),
graph_reverse_depends() now passes self instead of self.atom whenever
self.atom isn't a real Atom. self already carries the .cp/.category/.name
attributes intersects() needs for its name-only comparison, and since
self.cp (unslashed) never equals dep.cp ("cat/pkg"), that comparison
always takes the early-return branch, so the attributes intersects()
doesn't check (.repo, .slot, etc.) are never touched.

Bug: https://bugs.gentoo.org/981521
Signed-off-by: Matt Turner <mattst88@gentoo.org>
portage.dep.Atom.__new__ now interns instances in a module-level cache
keyed only by the atom string and parse flags, not by the constructor's
class. Constructing gentoolkit.atom.Atom with a string already interned
elsewhere as a plain portage.dep.Atom silently returns that cached
instance instead of one of our subclass, so methods we override (like
intersects()) resolve to portage's implementation instead of ours.

Reproduced with portage d52efac67: gentoolkit.atom.Atom() returned a
plain portage.dep.Atom whenever the same atom string had already been
interned by portage itself, which happens constantly in normal use. This
also explains why equery d was under-reporting some reverse
dependencies: portage.dep.Atom.intersects() and our own implementation
don't always agree.

Always calling object.__new__(cls) to bypass the cache broke CI, which
pins portage 3.0.70: through 3.0.81.3, portage.dep.Atom subclasses str
instead of using an intern cache, so object.__new__(cls) raised
"TypeError: object.__new__(Atom) is not safe, use str.__new__()".
Atom.__new__ now checks whether portage.dep.Atom is still a str subclass
and, if so, allocates via str.__new__(cls, atom) instead; that version
has no cache to bypass, so this is just correct allocation, not a
workaround.

Bug: https://bugs.gentoo.org/981521
Signed-off-by: Matt Turner <mattst88@gentoo.org>
@gentoo-bot
gentoo-bot merged commit c6e7fce into gentoo:master Aug 29, 2026
18 checks passed
@mattst88
mattst88 deleted the bug981521 branch August 29, 2026 17:28
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.

3 participants