Atom: drink up the string soup#1497
Conversation
44c1be6 to
ada5b2c
Compare
|
There's a test failure in |
The debug for the string_soup branch shows that it didn't account for the the conditional The debug output for the master branch shows it correctly select |
|
|
||
| if isinstance(mydep, Atom): | ||
| mydep = str(mydep) | ||
|
|
There was a problem hiding this comment.
The unevaluated_atom attribute is lost here, which causes the testSlotCollision failure.
There was a problem hiding this comment.
Superb find, thanks!
Yeah, this is why I think there's too many foo = str(atom) conversions in this PR right now. Honestly a miracle that I only managed to break a single test?
There was a problem hiding this comment.
Hmm, not sure.
There's only one place where the unevaluated_atom attribute is getattr'd with a fallback, in paren_enclose. All other accesses to the attribute would throw if they were operating on a str, so this is the only site where dropping the attribute could go wrong, right?
Yet if I patch that function to do
if unevaluated_atom:
if not hasattr(x, "unevaluated_atom"):
x = Atom(x).unevaluated_atom
else:
x = getattr(x, "unevaluated_atom", x)
it still fails.
There was a problem hiding this comment.
The specific code in match_from_list that will cause testSlotCollision to fail if you don't preserve unevaluated_atom is this:
if mydep.unevaluated_atom.use:
candidate_list = mylist
mylist = []
for x in candidate_list:
use = getattr(x, "use", None)
if use is not None:
if mydep.unevaluated_atom.use and not x.iuse.is_valid_flag(
mydep.unevaluated_atom.use.required
):
continue4370306 to
870884b
Compare
870884b to
d667d87
Compare
|
trying to put on some proper typing on portage.dep It seems that |
| atoms.append((x, atom)) | ||
|
|
||
| myvars = sorted(set(atoms)) | ||
| myvars = sorted(set(atoms), key=lambda t: str(t[0])) |
There was a problem hiding this comment.
It looks like we can omit this sort because myvars is only used to populate the cp_map variable.
|
|
||
| expanded = cpv_expand(mydep, mydb=mydb, use_cache=use_cache, settings=settings) | ||
| return Atom(orig_dep.replace(mydep, expanded, 1), allow_repo=True) | ||
| return Atom(str(orig_dep).replace(mydep, expanded, 1), allow_repo=True) |
There was a problem hiding this comment.
Should pass str(mydep) to replace in case it's an Atom.
| if mydep is not None: | ||
| tmp = len(mydep) >= 1 | ||
| if deplist[mypos][0] == "!": | ||
| if str(deplist[mypos]).startswith("!"): |
There was a problem hiding this comment.
They say startswith is marginally slower than slice comparison, and for the large number of these it might make sense to avoid startswith.
There was a problem hiding this comment.
Actually, it's better if we use the Atom.blocker attribute here since that also avoids the str conversion.
|
I discovered that |
They are public but deprecated, so let's just add a DeprecationWarning for now. Actually, we could use UserWarning to make them more noisy. |
|
|
||
|
|
||
| def match_to_list(mypkg, mylist): | ||
| def match_to_list(mypkg: Union[str, Atom], mylist: list) -> list: |
There was a problem hiding this comment.
mypkg should not be Atom, but _pkg_str or Package.
There was a problem hiding this comment.
I had a hard time following the typing for these functions, thanks.
Ideally these would be decoupled so that the auxiliary functions in the Atom file don't get Package objects, seeing that Package imports Atom... I'll see if I can unmangle them.
|
|
||
|
|
||
| def best_match_to_list(mypkg, mylist): | ||
| def best_match_to_list(mypkg: Union[str, Atom], mylist: list) -> Optional[Atom]: |
There was a problem hiding this comment.
mypkg should not be Atom, but _pkg_str or Package.
| if not isinstance(mydep, Atom): | ||
| if isinstance(mydep, Atom): | ||
| if mydep.blocker: | ||
| mydep = Atom(str(mydep).lstrip("!"), allow_wildcard=True, allow_repo=True) |
There was a problem hiding this comment.
It might not really be necessary to do this, and would be better to avoid if possible because it discards the unevaluated_atom.
| xs = x.cpv_split | ||
| elif hasattr(x, "cpv"): | ||
| # Package object | ||
| xs = x.cpv.cpv_split |
There was a problem hiding this comment.
This could be Atom since it has a cpv attribute, right?
| # Only package objects have 'use' and 'iuse' attributes | ||
| if not hasattr(x, "use"): | ||
| mylist.append(x) | ||
| continue |
There was a problem hiding this comment.
This could be Atom since it has a use attribute, right? We can't handle it like Package because it has no iuse attribute.
First step to making
portage.dep.Atomproperly typed.It still retains a
__str__method, as that will always be useful. Some call sites will still do something likestr(atom).split(...), because they usually operate on variant types ofstr | Atom | fooand are completely untyped :(Some properties of
Atomshould probably be dropped entirely, and some more be added. For memory efficiency, we may also want to synthesize some of them from the string representation as needed, instead of storing them.Also, it seems that
depgraph.pyis more cursed than previously thought possible, and writes toAtom._orig_atom. I've just added it as a field for now...Ultimately there's still a lot more
str(atom)users than I'd like, hence this is just a draft.There are a few remaining test failures that I am working on right now.
Note that there's also a selinux sandbox commit to fix some tests locally, that's ofc not related and I'll drop the commit later. Working with @WavyEbuilder to figure out why this only appears in tests.