From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 385B3158041 for ; Thu, 7 Mar 2024 18:49:20 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 20466E29B1; Thu, 7 Mar 2024 18:49:19 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 0472BE29B1 for ; Thu, 7 Mar 2024 18:49:19 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 4037C34300A for ; Thu, 7 Mar 2024 18:49:18 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id C3FE110B0 for ; Thu, 7 Mar 2024 18:49:16 +0000 (UTC) From: "Sam James" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Sam James" Message-ID: <1709837346.3a53501625e73483a86f2ee00696047a20682745.sam@gentoo> Subject: [gentoo-commits] proj/gentoolkit:master commit in: pym/gentoolkit/ X-VCS-Repository: proj/gentoolkit X-VCS-Files: pym/gentoolkit/dependencies.py X-VCS-Directories: pym/gentoolkit/ X-VCS-Committer: sam X-VCS-Committer-Name: Sam James X-VCS-Revision: 3a53501625e73483a86f2ee00696047a20682745 X-VCS-Branch: master Date: Thu, 7 Mar 2024 18:49:16 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 71506669-0b1e-498b-ab8d-c1cbc3828614 X-Archives-Hash: a8d991901c19e0f9a179e44c2332c68c commit: 3a53501625e73483a86f2ee00696047a20682745 Author: John Turner gmail com> AuthorDate: Thu Feb 22 20:50:40 2024 +0000 Commit: Sam James gentoo org> CommitDate: Thu Mar 7 18:49:06 2024 +0000 URL: https://gitweb.gentoo.org/proj/gentoolkit.git/commit/?id=3a535016 dependencies.py: rewrite graph_reverse_depends to pass tests The graph_reverse_depends method was not able to pass the unit tests introduced in the previous commits. It has been rewritten to pass them. This also has adding types to the method, and yields the results as an iterator rather than collecting them into a list in one shot. The printer callback parameter has been removed. This callback most likely existed so that results would be shown to the user as soon as they were available instead of delaying printing until the method completed, which could take seconds or minutes depending on the parameters. By making this method an iterator, the same effect is acheived by having the caller print every item as its yielded from the method. Signed-off-by: John Turner gmail.com> Signed-off-by: Sam James gentoo.org> pym/gentoolkit/dependencies.py | 102 +++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 66 deletions(-) diff --git a/pym/gentoolkit/dependencies.py b/pym/gentoolkit/dependencies.py index c6abff0..be5c71f 100644 --- a/pym/gentoolkit/dependencies.py +++ b/pym/gentoolkit/dependencies.py @@ -14,7 +14,7 @@ __all__ = ("Dependencies",) import itertools from functools import cache from enum import Enum -from typing import List, Dict +from typing import List, Dict, Iterable, Iterator, Set, Optional, Any, Union import portage from portage.dep import paren_reduce @@ -22,6 +22,7 @@ from portage.dep import paren_reduce from gentoolkit import errors from gentoolkit.atom import Atom from gentoolkit.query import Query +from gentoolkit.cpv import CPV # ======= # Classes @@ -52,10 +53,11 @@ class Dependencies(Query): """ - def __init__(self, query, parser=None): + def __init__(self, query: Any, parser: Any = None) -> None: Query.__init__(self, query) - self.use = [] - self.depatom = "" + self.use: List[str] = [] + self.depatom: Optional[Atom] = None + self.depth: Optional[int] = None # Allow a custom parser function: self.parser = parser if parser else self._parser @@ -185,15 +187,13 @@ class Dependencies(Query): def graph_reverse_depends( self, - pkgset=None, - max_depth=-1, - only_direct=True, - printer_fn=None, + pkgset: Iterable[Union[str, CPV]], + max_depth: Optional[int] = None, + only_direct: bool = True, # The rest of these are only used internally: - depth=0, - seen=None, - result=None, - ): + depth: int = 0, + seen: Optional[Set[str]] = None, + ) -> Iterator["Dependencies"]: """Graph direct reverse dependencies for self. Example usage: @@ -201,10 +201,10 @@ class Dependencies(Query): >>> ffmpeg = Dependencies('media-video/ffmpeg-9999') >>> # I only care about installed packages that depend on me: ... from gentoolkit.helpers import get_installed_cpvs - >>> # I want to pass in a sorted list. We can pass strings or - ... # Package or Atom types, so I'll use Package to sort: + >>> # I want to pass in a list. We can pass strings or + ... # Package or Atom types. ... from gentoolkit.package import Package - >>> installed = sorted(get_installed_cpvs()) + >>> installed = get_installed_cpvs() >>> deptree = ffmpeg.graph_reverse_depends( ... only_direct=False, # Include indirect revdeps ... pkgset=installed) # from installed pkgset @@ -212,82 +212,52 @@ class Dependencies(Query): 24 @type pkgset: iterable - @keyword pkgset: sorted pkg cpv strings or anything sublassing + @keyword pkgset: pkg cpv strings or anything sublassing L{gentoolkit.cpv.CPV} to use for calculate our revdep graph. - @type max_depth: int + @type max_depth: optional @keyword max_depth: Maximum depth to recurse if only_direct=False. - -1 means no maximum depth; - 0 is the same as only_direct=True; + None means no maximum depth; + 0 is the same as only_direct=True; >0 means recurse only this many times; @type only_direct: bool @keyword only_direct: to recurse or not to recurse - @type printer_fn: callable - @keyword printer_fn: If None, no effect. If set, it will be applied to - each L{gentoolkit.atom.Atom} object as it is added to the results. - @rtype: list + @rtype: iterable @return: L{gentoolkit.dependencies.Dependencies} objects """ - if not pkgset: - err = ( - "%s kwarg 'pkgset' must be set. " - "Can be list of cpv strings or any 'intersectable' object." - ) - raise errors.GentoolkitFatalError(err % (self.__class__.__name__,)) if seen is None: seen = set() - if result is None: - result = list() - if depth == 0: - pkgset = tuple(Dependencies(x) for x in pkgset) - - pkgdep = None - for pkgdep in pkgset: + for pkgdep in (Dependencies(pkg) for pkg in pkgset): if self.cp not in pkgdep.get_raw_depends(): # fast path for obviously non-matching packages. This saves # us the work of instantiating a whole Atom() for *every* # dependency of *every* package in pkgset. continue - all_depends = pkgdep.get_all_depends() - dep_is_displayed = False - for dep in all_depends: - # TODO: Add ability to determine if dep is enabled by USE flag. - # Check portage.dep.use_reduce + found_match = False + for dep in pkgdep.get_all_depends(): if dep.intersects(self): + pkgdep.depatom = dep pkgdep.depth = depth - pkgdep.matching_dep = dep - if printer_fn is not None: - printer_fn(pkgdep, dep_is_displayed=dep_is_displayed) - result.append(pkgdep) - dep_is_displayed = True - - # if --indirect specified, call ourselves again with the dep - # Do not call if we have already called ourselves. + yield pkgdep + found_match = True + if ( - dep_is_displayed - and not only_direct + found_match and pkgdep.cpv not in seen - and (depth < max_depth or max_depth == -1) + and only_direct is False + and (max_depth is None or depth < max_depth) ): seen.add(pkgdep.cpv) - result.append( - pkgdep.graph_reverse_depends( - pkgset=pkgset, - max_depth=max_depth, - only_direct=only_direct, - printer_fn=printer_fn, - depth=depth + 1, - seen=seen, - result=result, - ) + yield from pkgdep.graph_reverse_depends( + pkgset=pkgset, + only_direct=False, + max_depth=max_depth, + depth=depth + 1, + seen=seen, ) - if depth == 0: - return result - return pkgdep - def _parser(self, deps, use_conditional=None, depth=0): """?DEPEND file parser.