public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Sam James" <sam@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/gentoolkit:master commit in: pym/gentoolkit/
Date: Thu,  7 Mar 2024 18:49:16 +0000 (UTC)	[thread overview]
Message-ID: <1709837346.3a53501625e73483a86f2ee00696047a20682745.sam@gentoo> (raw)

commit:     3a53501625e73483a86f2ee00696047a20682745
Author:     John Turner <jturner.usa <AT> gmail <DOT> com>
AuthorDate: Thu Feb 22 20:50:40 2024 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> 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 <jturner.usa <AT> gmail.com>
Signed-off-by: Sam James <sam <AT> 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.
 


             reply	other threads:[~2024-03-07 18:49 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-07 18:49 Sam James [this message]
  -- strict thread matches above, loose matches on Subject: below --
2024-05-03  5:55 [gentoo-commits] proj/gentoolkit:master commit in: pym/gentoolkit/ Sam James
2024-03-07 15:08 Sam James
2024-02-17  0:01 Sam James
2024-02-16 20:39 Sam James
2024-02-16 20:39 Sam James
2024-02-16 20:39 Sam James
2022-12-14  9:24 Sam James
2022-07-10  7:53 Brian Dolbec
2022-07-10  7:53 Brian Dolbec
2021-09-21 21:01 Matt Turner
2020-10-13 14:14 Brian Dolbec
2020-10-09  6:29 Georgy Yakovlev
2020-04-24  8:06 Michał Górny
2019-07-29  0:51 Zac Medico
2019-05-11 22:43 Virgil Dupras
2018-09-17 23:32 Virgil Dupras
2017-09-06 18:33 Paul Varner
2016-09-15 16:02 Brian Dolbec
2016-08-16 16:05 Paul Varner
2016-07-25 18:04 Paul Varner
2016-07-08 15:37 Brian Dolbec
2015-10-22 16:13 Paul Varner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1709837346.3a53501625e73483a86f2ee00696047a20682745.sam@gentoo \
    --to=sam@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox