commit: e40b7253f505d3d6c48743ab539e89d308e725d6
Author: Brian Harring <ferringb <AT> gmail <DOT> com>
AuthorDate: Sat Nov 22 10:28:39 2025 +0000
Commit: Brian Harring <ferringb <AT> gmail <DOT> com>
CommitDate: Sat Nov 22 18:19:28 2025 +0000
URL:
https://gitweb.gentoo.org/proj/pkgcore/pkgcheck.git/commit/?id=e40b7253
chore: minor code cleanup
Roughly:
* replace `raise NotImplemented` with abc.ABC. The latter should
be used- it just didn't exist at the time.
* if a generator is a single `yield from`, just return the thing
being consumed. Drop the intermediate frame and yield traversing
the frames.
* Add some annotations as I'm going for things that caught my eye.
Signed-off-by: Brian Harring <ferringb <AT> gmail.com>
src/pkgcheck/addons/git.py | 18 +++++++++++------
src/pkgcheck/checks/network.py | 13 ++++++++----
src/pkgcheck/sources.py | 45 ++++++++++++++++++------------------------
3 files changed, 40 insertions(+), 36 deletions(-)
diff --git a/src/pkgcheck/addons/git.py b/src/pkgcheck/addons/git.py
index 302c5bc1..2c8f1094 100644
--- a/src/pkgcheck/addons/git.py
+++ b/src/pkgcheck/addons/git.py
@@ -1,16 +1,18 @@
"""Git specific support and addon."""
+import abc
import argparse
import os
import re
import shlex
import subprocess
+import tempfile
+import typing
from collections import defaultdict, deque
from dataclasses import dataclass
from datetime import datetime
from functools import partial
from itertools import takewhile
-import tempfile
from pathspec import PathSpec
from pkgcore.ebuild import cpv
@@ -142,7 +144,10 @@ class GitLog:
return line.rstrip()
-class _ParseGitRepo:
+T = typing.TypeVar("T")
+
+
+class _ParseGitRepo(typing.Generic[T], abc.ABC):
"""Generic iterator for custom git log output parsing support."""
# git command to run on the targeted repo
@@ -169,8 +174,9 @@ class _ParseGitRepo:
def __iter__(self):
return self
- def __next__(self):
- raise NotImplementedError(self.__next__)
+ @abc.abstractmethod
+ def __next__(self) -> T:
+ pass
@property
def changes(self):
@@ -201,7 +207,7 @@ class _ParseGitRepo:
continue
-class GitRepoCommits(_ParseGitRepo):
+class GitRepoCommits(_ParseGitRepo["GitCommit"]):
"""Parse git log output into an iterator of commit objects."""
_format = (
@@ -229,7 +235,7 @@ class GitRepoCommits(_ParseGitRepo):
return GitCommit(commit_hash, commit_time, author, committer, message,
ImmutableDict(pkgs))
-class GitRepoPkgs(_ParseGitRepo):
+class GitRepoPkgs(_ParseGitRepo["GitPkgChange"]):
"""Parse git log output into an iterator of package change objects."""
_format = (
diff --git a/src/pkgcheck/checks/network.py b/src/pkgcheck/checks/network.py
index b26603b1..fb5e2fd1 100644
--- a/src/pkgcheck/checks/network.py
+++ b/src/pkgcheck/checks/network.py
@@ -1,8 +1,10 @@
"""Various checks that require network support."""
+import abc
import re
import socket
import traceback
+import typing
import urllib.request
from functools import partial
@@ -96,7 +98,7 @@ class RequestError(_RequestException):
"""Wrapper for generic requests exception."""
-class _UrlCheck(NetworkCheck):
+class _UrlCheck(abc.ABC, NetworkCheck):
"""Generic URL verification check requiring network support."""
_source = sources.LatestVersionRepoSource
@@ -194,9 +196,12 @@ class _UrlCheck(NetworkCheck):
result = result._create(**attrs, pkg=pkg)
self.results_q.put([result])
- def _get_urls(self, pkg):
- """Get URLs to verify for a given package."""
- raise NotImplementedError
+ @abc.abstractmethod
+ def _get_urls(self, pkg) -> typing.Iterable[tuple[str, str]]:
+ """Get URLs to verify for a given package.
+
+ yields pairs of (key, url)
+ """
def _schedule_check(self, func, attr, url, executor, futures, **kwargs):
"""Schedule verification method to run in a separate thread against a
given URL.
diff --git a/src/pkgcheck/sources.py b/src/pkgcheck/sources.py
index 2d0832cd..b94f9758 100644
--- a/src/pkgcheck/sources.py
+++ b/src/pkgcheck/sources.py
@@ -1,6 +1,9 @@
"""Custom package sources used for feeding checks."""
+import abc
+import itertools
import os
+import typing
from collections import defaultdict, deque
from collections.abc import Set
from dataclasses import dataclass
@@ -14,9 +17,9 @@ from snakeoil import klass
from snakeoil.osutils import listdir_files, pjoin
from . import addons, base
-from .bash import ParseTree
from .addons.eclass import Eclass, EclassAddon
from .addons.profiles import ProfileAddon, ProfileNode
+from .bash import ParseTree
from .packages import FilteredPkg, RawCPV, WrappedPkg
@@ -31,10 +34,10 @@ class Source:
self.source = source
def __iter__(self):
- yield from self.source
+ return iter(self.source)
def itermatch(self, restrict, **kwargs):
- yield from self.source
+ return iter(self.source)
class EmptySource(Source):
@@ -150,7 +153,7 @@ class FilteredRepoSource(RepoSource):
self._pkg_filter = pkg_filter
def itermatch(self, restrict, **kwargs):
- yield from self._pkg_filter(super().itermatch(restrict, **kwargs))
+ return self._pkg_filter(super().itermatch(restrict, **kwargs))
class FilteredPackageRepoSource(FilteredRepoSource):
@@ -255,7 +258,7 @@ class RawRepoSource(RepoSource):
super().__init__(options, source)
def itermatch(self, restrict, **kwargs):
- yield from super().itermatch(restrict, raw_pkg_cls=RawCPV, **kwargs)
+ return super().itermatch(restrict, raw_pkg_cls=RawCPV, **kwargs)
class RestrictionRepoSource(RepoSource):
@@ -267,7 +270,7 @@ class RestrictionRepoSource(RepoSource):
def itermatch(self, restrict, **kwargs):
restrict = packages.AndRestriction(*(restrict, self.restriction))
- yield from super().itermatch(restrict, **kwargs)
+ return super().itermatch(restrict, **kwargs)
class UnmaskedRepoSource(RepoSource):
@@ -286,7 +289,7 @@ class UnmaskedRepoSource(RepoSource):
)
def itermatch(self, restrict, **kwargs):
- yield from self._filtered_repo.itermatch(restrict, **kwargs)
+ return self._filtered_repo.itermatch(restrict, **kwargs)
class _SourcePkg(WrappedPkg):
@@ -343,27 +346,16 @@ class EclassParseRepoSource(EclassRepoSource):
yield _ParsedEclass(data, eclass=eclass)
-class _CombinedSource(RepoSource):
+class _CombinedSource(abc.ABC, RepoSource):
"""Generic source combining packages into similar chunks."""
- def keyfunc(self, pkg):
+ @abc.abstractmethod
+ def keyfunc(self, pkg) -> typing.Hashable:
"""Function targeting attribute used to group packages."""
- raise NotImplementedError(self.keyfunc)
def itermatch(self, restrict, **kwargs):
- key = None
- chunk = None
- for pkg in super().itermatch(restrict, **kwargs):
- new = self.keyfunc(pkg)
- if new == key:
- chunk.append(pkg)
- else:
- if chunk is not None:
- yield chunk
- chunk = [pkg]
- key = new
- if chunk is not None:
- yield chunk
+ for _key, pkgs in itertools.groupby(super().itermatch(restrict,
**kwargs), self.keyfunc):
+ yield list(pkgs)
class PackageRepoSource(_CombinedSource):
@@ -386,11 +378,12 @@ class RepositoryRepoSource(RepoSource):
scope = base.repo_scope
-class _FilteredSource(RawRepoSource):
+class _FilteredSource(abc.ABC, RawRepoSource):
"""Generic source yielding selected attribute from matching packages."""
- def keyfunc(self, pkg):
- raise NotImplementedError(self.keyfunc)
+ @abc.abstractmethod
+ def keyfunc(self, pkg) -> typing.Hashable:
+ pass
def itermatch(self, restrict, **kwargs):
key = None