aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur Zamarin <arthurzam@gentoo.org>2022-10-13 21:01:11 +0300
committerArthur Zamarin <arthurzam@gentoo.org>2022-10-13 21:01:11 +0300
commit7907e967237c9386346f69c0327858dba58a6001 (patch)
tree964f11044c378e4372fed9a4d6b3b8e56c43c3b7
parentPythonCheck: warn about use of distutils-r1 non-PEP517 mode (diff)
downloadpkgcheck-7907e967237c9386346f69c0327858dba58a6001.tar.gz
pkgcheck-7907e967237c9386346f69c0327858dba58a6001.tar.bz2
pkgcheck-7907e967237c9386346f69c0327858dba58a6001.zip
PythonCheck: refactor and merge with PythonWrongUsageCheck
Signed-off-by: Arthur Zamarin <arthurzam@gentoo.org>
-rw-r--r--src/pkgcheck/checks/python.py487
-rw-r--r--testdata/data/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/expected.json6
-rw-r--r--testdata/data/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/fix.patch28
-rw-r--r--testdata/data/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/expected.json4
-rw-r--r--testdata/data/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/fix.patch (renamed from testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/fix.patch)12
-rw-r--r--testdata/data/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/expected.json5
-rw-r--r--testdata/data/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/fix.patch13
-rw-r--r--testdata/data/repos/python/PythonCheck/PythonHasVersionUsage/expected.json2
-rw-r--r--testdata/data/repos/python/PythonCheck/PythonHasVersionUsage/fix.patch52
-rw-r--r--testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/expected.json6
-rw-r--r--testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/fix.patch28
-rw-r--r--testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/expected.json4
-rw-r--r--testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/expected.json5
-rw-r--r--testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/fix.patch13
-rw-r--r--testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/expected.json2
-rw-r--r--testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/fix.patch52
-rw-r--r--testdata/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild (renamed from testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild)0
-rw-r--r--testdata/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-1.ebuild (renamed from testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-1.ebuild)0
-rw-r--r--testdata/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild (renamed from testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild)0
-rw-r--r--testdata/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild (renamed from testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild)0
-rw-r--r--testdata/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-2.ebuild (renamed from testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-2.ebuild)0
-rw-r--r--testdata/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild (renamed from testdata/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild)0
-rw-r--r--testdata/repos/python/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild (renamed from testdata/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild)0
-rw-r--r--testdata/repos/python/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild (renamed from testdata/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild)0
24 files changed, 341 insertions, 378 deletions
diff --git a/src/pkgcheck/checks/python.py b/src/pkgcheck/checks/python.py
index a1d5ff5f..fc9a58e7 100644
--- a/src/pkgcheck/checks/python.py
+++ b/src/pkgcheck/checks/python.py
@@ -150,6 +150,86 @@ class DistutilsNonPEP517Build(results.VersionResult, results.Warning):
)
+class PythonHasVersionUsage(results.LinesResult, results.Style):
+ """Package uses has_version inside ``python_check_deps``.
+
+ Ebuilds which declare the ``python_check_deps`` function (which tests
+ Python implementations for matching dependencies) should use the special
+ ``python_has_version`` function (instead of ``has_version``) for enhanced
+ log output and defaults [#]_.
+
+ .. [#] https://projects.gentoo.org/python/guide/any.html#dependencies
+ """
+
+ @property
+ def desc(self):
+ return f'usage of has_version {self.lines_str}, replace with python_has_version'
+
+
+class PythonHasVersionMissingPythonUseDep(results.LineResult, results.Error):
+ """Package calls ``python_has_version`` or ``has_version`` without
+ ``[${PYTHON_USEDEP}]`` suffix.
+
+ All calls to ``python_has_version`` or ``has_version`` inside
+ ``python_check_deps`` should contain ``[${PYTHON_USEDEP}]`` suffix for the
+ dependency argument [#]_.
+
+ .. [#] https://projects.gentoo.org/python/guide/any.html#dependencies
+ """
+
+ @property
+ def desc(self):
+ return f'line: {self.lineno}: missing [${{PYTHON_USEDEP}}] suffix for argument "{self.line}"'
+
+
+class PythonAnyMismatchedUseHasVersionCheck(results.VersionResult, results.Warning):
+ """Package has mismatch in dependency's use flags between call to
+ ``python_gen_any_dep`` and ``python_has_version``.
+
+ For every dependency used under ``python_gen_any_dep``, the check for a
+ matching python implementation in ``python_has_version`` should match the
+ exact use flags [#]_.
+
+ .. [#] https://projects.gentoo.org/python/guide/any.html#dependencies
+ """
+
+ def __init__(self, dep_category, dep_atom, use_flags, location, **kwargs):
+ super().__init__(**kwargs)
+ self.dep_category = dep_category
+ self.dep_atom = dep_atom
+ self.use_flags = tuple(use_flags)
+ self.location = location
+
+ @property
+ def desc(self):
+ s = pluralism(self.use_flags)
+ use_flags = ', '.join(map(str, self.use_flags))
+ return f'{self.dep_category}: mismatch for {self.dep_atom} check use flag{s} [{use_flags}] in {self.location}'
+
+
+class PythonAnyMismatchedDepHasVersionCheck(results.VersionResult, results.Warning):
+ """Package has mismatch in dependencies between call to
+ ``python_gen_any_dep`` and ``python_has_version``.
+
+ For every dependency used under ``python_gen_any_dep``, a matching check
+ for a matching python implementation in ``python_has_version`` should
+ exist [#]_.
+
+ .. [#] https://projects.gentoo.org/python/guide/any.html#dependencies
+ """
+
+ def __init__(self, dep_category, dep_atom, use_flags, location, **kwargs):
+ super().__init__(**kwargs)
+ self.dep_category = dep_category
+ self.dep_atom = dep_atom
+ self.use_flags = tuple(use_flags)
+ self.location = location
+
+ @property
+ def desc(self):
+ use_flags = ', '.join(map(str, self.use_flags))
+ return f'{self.dep_category}: missing check for {self.dep_atom}[{use_flags}] in {self.location!r}'
+
class PythonCheck(Check):
"""Python eclass checks.
@@ -162,8 +242,30 @@ class PythonCheck(Check):
MissingPythonEclass, PythonMissingRequiredUse,
PythonMissingDeps, PythonRuntimeDepInAnyR1, PythonEclassError,
DistutilsNonPEP517Build,
+ PythonHasVersionUsage,
+ PythonHasVersionMissingPythonUseDep,
+ PythonAnyMismatchedUseHasVersionCheck,
+ PythonAnyMismatchedDepHasVersionCheck,
])
+ has_version_known_flags = {
+ '-b': 'BDEPEND',
+ '-r': 'RDEPEND',
+ '-d': 'DEPEND',
+ '--host-root': 'BDEPEND',
+ }
+
+ has_version_default = {
+ 'has_version': 'DEPEND',
+ 'python_has_version': 'BDEPEND',
+ }
+
+ eclass_any_dep_func = {
+ 'python-single-r1': 'python_gen_cond_dep',
+ 'python-any-r1': 'python_gen_any_dep',
+ 'python-r1': 'python_gen_any_dep',
+ }
+
def scan_tree_recursively(self, deptree, expected_cls):
for x in deptree:
if not isinstance(x, expected_cls):
@@ -212,65 +314,128 @@ class PythonCheck(Check):
return True
return False
- def check_pep517_depend(self, item):
- """Check Python ebuilds for missing optional dependencies.
+ def check_pep517(self, pkg):
+ """Check Python ebuilds for whether PEP517 mode is used and missing
+ optional dependencies.
The problematic case for us is ``DISTUTILS_OPTIONAL`` and
``DISTUTILS_USE_PEP517 != no`` but ``${DISTUTILS_DEPS}`` is not in
the ebuild.
"""
has_distutils_optional = None
- has_distutils_pep517_non_no = None
-
- # We're not interested in testing fake objects from TestPythonCheck
- if not isinstance(item, sources._ParsedPkg) or not hasattr(item, 'tree'): # pragma: no cover
- return True
+ has_distutils_deps = False
+ pep517_value = None
- for var_node, _ in bash.var_assign_query.captures(item.tree.root_node):
- var_name = item.node_str(var_node.child_by_field_name('name'))
+ for var_node, _ in bash.var_assign_query.captures(pkg.tree.root_node):
+ var_name = pkg.node_str(var_node.child_by_field_name('name'))
if var_name == "DISTUTILS_OPTIONAL":
has_distutils_optional = True
+ elif var_name == "DISTUTILS_USE_PEP517":
+ pep517_value = pkg.node_str(var_node.children[-1])
- if "DISTUTILS_DEPS" in item.node_str(var_node.parent):
+ if "DISTUTILS_DEPS" in pkg.node_str(var_node.parent):
# If they're referencing the eclass' dependency variable,
# there's nothing for us to do anyway.
- return True
+ has_distutils_deps = True
- if var_name == "DISTUTILS_USE_PEP517" and not has_distutils_pep517_non_no:
- var_val = item.node_str(var_node.children[-1])
- # For DISTUTILS_USE_PEP517=no, the eclass doesn't
- # provide ${DISTUTILS_DEPS}.
- has_distutils_pep517_non_no = (var_val != "no")
+ if pep517_value is None:
+ yield DistutilsNonPEP517Build(pkg=pkg)
+ elif has_distutils_optional and not has_distutils_deps and pep517_value != "no":
+ # We always need BDEPEND for these if != no.
+ # We are looking for USE-conditional on appropriate target
+ # flag, with dep on dev-python/gpep517.
+ if "dev-python/gpep517" not in iflatten_instance(pkg.bdepend, atom):
+ yield PythonMissingDeps("BDEPEND", pkg=pkg, dep_value="DISTUTILS_DEPS")
- if has_distutils_optional and has_distutils_pep517_non_no:
- # We always need BDEPEND for these if != no.
- # We are looking for USE-conditional on appropriate target
- # flag, with dep on dev-python/gpep517.
- return "dev-python/gpep517" in iflatten_instance(item.bdepend, atom)
- return True
+ @staticmethod
+ def _prepare_deps(deps: str):
+ try:
+ deps_str = deps.strip('\"\'').replace('\\$', '$').replace('${PYTHON_USEDEP}', 'pkgcheck_python_usedep')
+ return iflatten_instance(DepSet.parse(deps_str, atom), atom)
+ except DepsetParseError:
+ # if we are unable to parse that dep's string, skip it
+ return ()
- def check_pep517_mode(self, item):
- """Check whether PEP517 mode is used."""
- # We're not interested in testing fake objects from TestPythonCheck
- if not isinstance(item, sources._ParsedPkg) or not hasattr(item, 'tree'): # pragma: no cover
- return True
+ def build_python_gen_any_dep_calls(self, pkg, any_dep_func):
+ check_deps = defaultdict(set)
+ for var_node in pkg.global_query(bash.var_assign_query):
+ name = pkg.node_str(var_node.child_by_field_name('name'))
+ if name in {'DEPEND', 'BDEPEND'}:
+ for call_node, _ in bash.cmd_query.captures(var_node):
+ call_name = pkg.node_str(call_node.child_by_field_name('name'))
+ if call_name == any_dep_func and len(call_node.children) > 1:
+ check_deps[name].update(self._prepare_deps(
+ pkg.node_str(call_node.children[1])))
+ return {dep: frozenset(atoms) for dep, atoms in check_deps.items()}
- for var_node, _ in bash.var_assign_query.captures(item.tree.root_node):
- var_name = item.node_str(var_node.child_by_field_name('name'))
+ def report_mismatch_check_deps(self, pkg, python_check_deps, has_version_checked_deps, any_dep_func):
+ for dep_type in frozenset(python_check_deps.keys()).union(
+ has_version_checked_deps.keys()):
+ extra = has_version_checked_deps[dep_type] - python_check_deps.get(dep_type, set())
+ missing = python_check_deps.get(dep_type, set()) - has_version_checked_deps[dep_type]
+ for diff, other, location in (
+ (extra, missing, any_dep_func),
+ (missing, extra, "python_check_deps"),
+ ):
+ for dep in diff:
+ dep_atom = str(dep.versioned_atom)
+ for other_dep in other:
+ if dep_atom == str(other_dep.versioned_atom):
+ if diff_flags := set(other_dep.use) - set(dep.use):
+ yield PythonAnyMismatchedUseHasVersionCheck(pkg=pkg,
+ dep_category=dep_type, dep_atom=dep_atom,
+ use_flags=diff_flags, location=location)
+ break
+ else:
+ use_flags = {'${PYTHON_USEDEP}'} | set(dep.use) \
+ - {'pkgcheck_python_usedep'}
+ yield PythonAnyMismatchedDepHasVersionCheck(pkg=pkg,
+ dep_category=dep_type, dep_atom=dep_atom,
+ use_flags=use_flags, location=location)
- if var_name == "DISTUTILS_USE_PEP517":
- return True
+ @staticmethod
+ def _prepare_dep_type(pkg, dep_type: str) -> str:
+ if dep_type == 'BDEPEND' not in pkg.eapi.dep_keys:
+ return 'DEPEND'
+ return dep_type
- return False
+ def check_python_check_deps(self, pkg, func_node, python_check_deps, any_dep_func):
+ has_version_checked_deps = defaultdict(set)
+ has_version_lines = set()
+ for node, _ in bash.cmd_query.captures(func_node):
+ call_name = pkg.node_str(node.child_by_field_name('name'))
+ if call_name == "has_version":
+ lineno, _ = node.start_point
+ has_version_lines.add(lineno + 1)
+ if dep_mode := self.has_version_default.get(call_name, None):
+ dep_mode = self._prepare_dep_type(pkg, dep_mode)
+ for arg in node.children[1:]:
+ arg_name = pkg.node_str(arg)
+ if new_dep_mode := self.has_version_known_flags.get(arg_name, None):
+ dep_mode = self._prepare_dep_type(pkg, new_dep_mode)
+ else:
+ arg_name = arg_name.strip('\"\'')
+ if not USE_FLAGS_PYTHON_USEDEP.search(arg_name):
+ lineno, _ = arg.start_point
+ yield PythonHasVersionMissingPythonUseDep(
+ lineno=lineno+1, line=arg_name, pkg=pkg)
+ else:
+ has_version_checked_deps[dep_mode].update(
+ self._prepare_deps(arg_name))
+
+ if has_version_lines:
+ yield PythonHasVersionUsage(lines=sorted(has_version_lines), pkg=pkg)
+
+ yield from self.report_mismatch_check_deps(pkg, python_check_deps, has_version_checked_deps, any_dep_func)
def feed(self, pkg):
try:
eclass = get_python_eclass(pkg)
- except ValueError as e:
- yield PythonEclassError(str(e), pkg=pkg)
+ except ValueError as exc:
+ yield PythonEclassError(str(exc), pkg=pkg)
return
if eclass is None:
@@ -291,47 +456,52 @@ class PythonCheck(Check):
if highest_found is not None:
attr, p = highest_found
if attr in ("rdepend", "pdepend"):
- recomm = "python-r1 or python-single-r1"
+ recommendation = "python-r1 or python-single-r1"
else:
- recomm = "python-any-r1"
- yield MissingPythonEclass(recomm, attr.upper(), str(p), pkg=pkg)
+ recommendation = "python-any-r1"
+ yield MissingPythonEclass(recommendation, attr.upper(), str(p), pkg=pkg)
elif eclass in ('python-r1', 'python-single-r1'):
# grab Python implementations from IUSE
- iuse = [x.lstrip('+-') for x in pkg.iuse]
- flags = {x[len(IUSE_PREFIX):] for x in iuse if x.startswith(IUSE_PREFIX)}
- s_flags = {
- x[len(IUSE_PREFIX_S):] for x in iuse if x.startswith(IUSE_PREFIX_S)}
+ iuse = {x.lstrip('+-') for x in pkg.iuse}
if eclass == 'python-r1':
+ flags = {x[len(IUSE_PREFIX):] for x in iuse if x.startswith(IUSE_PREFIX)}
req_use_args = (flags, IUSE_PREFIX, OrRestriction)
else:
- req_use_args = (s_flags, IUSE_PREFIX_S, JustOneRestriction)
+ flags = {x[len(IUSE_PREFIX_S):] for x in iuse if x.startswith(IUSE_PREFIX_S)}
+ req_use_args = (flags, IUSE_PREFIX_S, JustOneRestriction)
if not self.check_required_use(pkg.required_use, *req_use_args):
yield PythonMissingRequiredUse(pkg=pkg)
if not self.check_depend(pkg.rdepend, *(req_use_args[:2])):
yield PythonMissingDeps('RDEPEND', pkg=pkg)
- if "distutils-r1" in pkg.inherited:
- if not self.check_pep517_mode(pkg):
- yield DistutilsNonPEP517Build(pkg=pkg)
- if not self.check_pep517_depend(pkg):
- yield PythonMissingDeps("BDEPEND", pkg=pkg, dep_value="DISTUTILS_DEPS")
else: # python-any-r1
for attr in ("rdepend", "pdepend"):
for p in iflatten_instance(getattr(pkg, attr), atom):
if not p.blocks and p.key in INTERPRETERS:
yield PythonRuntimeDepInAnyR1(attr.upper(), str(p), pkg=pkg)
break
- for attr in ("depend", "bdepend"):
- for p in iflatten_instance(getattr(pkg, attr), atom):
- if not p.blocks and p.key in INTERPRETERS:
- break
- else:
- continue
- break
- else:
+ if not any(
+ not p.blocks and p.key in INTERPRETERS
+ for attr in ("depend", "bdepend")
+ for p in iflatten_instance(getattr(pkg, attr), atom)
+ ):
yield PythonMissingDeps('DEPEND', pkg=pkg)
+ # We're not interested in testing fake objects from TestPythonCheck
+ if eclass is None or not isinstance(pkg, sources._ParsedPkg) or not hasattr(pkg, 'tree'): # pragma: no cover
+ return
+
+ if "distutils-r1" in pkg.inherited:
+ yield from self.check_pep517(pkg)
+
+ any_dep_func = self.eclass_any_dep_func[eclass]
+ python_check_deps = self.build_python_gen_any_dep_calls(pkg, any_dep_func)
+ for func_node, _ in bash.func_query.captures(pkg.tree.root_node):
+ func_name = pkg.node_str(func_node.child_by_field_name('name'))
+ if func_name == "python_check_deps":
+ yield from self.check_python_check_deps(pkg, func_node, python_check_deps, any_dep_func)
+
class PythonCompatUpdate(results.VersionResult, results.Info):
"""``PYTHON_COMPAT`` can be updated to support newer python version(s)."""
@@ -500,210 +670,3 @@ class PythonGHDistfileSuffixCheck(Check):
if GITHUB_ARCHIVE_RE.match(uri):
yield PythonGHDistfileSuffix(f.filename, uri, pkg=pkg)
break
-
-
-class PythonHasVersionUsage(results.LinesResult, results.Style):
- """Package uses has_version inside ``python_check_deps``.
-
- Ebuilds which declare the ``python_check_deps`` function (which tests
- Python implementations for matching dependencies) should use the special
- ``python_has_version`` function (instead of ``has_version``) for enhanced
- log output and defaults [#]_.
-
- .. [#] https://projects.gentoo.org/python/guide/any.html#dependencies
- """
-
- @property
- def desc(self):
- return f'usage of has_version {self.lines_str}, replace with python_has_version'
-
-
-class PythonHasVersionMissingPythonUseDep(results.LineResult, results.Error):
- """Package calls ``python_has_version`` or ``has_version`` without
- ``[${PYTHON_USEDEP}]`` suffix.
-
- All calls to ``python_has_version`` or ``has_version`` inside
- ``python_check_deps`` should contain ``[${PYTHON_USEDEP}]`` suffix for the
- dependency argument [#]_.
-
- .. [#] https://projects.gentoo.org/python/guide/any.html#dependencies
- """
-
- @property
- def desc(self):
- return f'line: {self.lineno}: missing [${{PYTHON_USEDEP}}] suffix for argument "{self.line}"'
-
-
-class PythonAnyMismatchedUseHasVersionCheck(results.VersionResult, results.Warning):
- """Package has mismatch in dependency's use flags between call to
- ``python_gen_any_dep`` and ``python_has_version``.
-
- For every dependency used under ``python_gen_any_dep``, the check for a
- matching python implementation in ``python_has_version`` should match the
- exact use flags [#]_.
-
- .. [#] https://projects.gentoo.org/python/guide/any.html#dependencies
- """
-
- def __init__(self, dep_category, dep_atom, use_flags, location, **kwargs):
- super().__init__(**kwargs)
- self.dep_category = dep_category
- self.dep_atom = dep_atom
- self.use_flags = tuple(use_flags)
- self.location = location
-
- @property
- def desc(self):
- s = pluralism(self.use_flags)
- use_flags = ', '.join(map(str, self.use_flags))
- return f'{self.dep_category}: mismatch for {self.dep_atom} check use flag{s} [{use_flags}] in {self.location}'
-
-
-class PythonAnyMismatchedDepHasVersionCheck(results.VersionResult, results.Warning):
- """Package has mismatch in dependencies between call to
- ``python_gen_any_dep`` and ``python_has_version``.
-
- For every dependency used under ``python_gen_any_dep``, a matching check
- for a matching python implementation in ``python_has_version`` should
- exist [#]_.
-
- .. [#] https://projects.gentoo.org/python/guide/any.html#dependencies
- """
-
- def __init__(self, dep_category, dep_atom, use_flags, location, **kwargs):
- super().__init__(**kwargs)
- self.dep_category = dep_category
- self.dep_atom = dep_atom
- self.use_flags = tuple(use_flags)
- self.location = location
-
- @property
- def desc(self):
- use_flags = ', '.join(map(str, self.use_flags))
- return f'{self.dep_category}: missing check for {self.dep_atom}[{use_flags}] in {self.location!r}'
-
-
-class PythonWrongUsageCheck(Check):
- """Check ebuilds for wrong usage of Python eclasses features.
-
- This check parses the ebuild and checks for more advanced failures/misuses
- of API.
- """
-
- _source = sources.EbuildParseRepoSource
- known_results = frozenset({
- PythonHasVersionUsage,
- PythonHasVersionMissingPythonUseDep,
- PythonAnyMismatchedUseHasVersionCheck,
- PythonAnyMismatchedDepHasVersionCheck,
- })
-
- has_version_known_flags = {
- '-b': 'BDEPEND',
- '-r': 'RDEPEND',
- '-d': 'DEPEND',
- '--host-root': 'BDEPEND',
- }
-
- has_version_default = {
- 'has_version': 'DEPEND',
- 'python_has_version': 'BDEPEND',
- }
-
- eclass_any_dep_func = {
- 'python-single-r1': 'python_gen_cond_dep',
- 'python-any-r1': 'python_gen_any_dep',
- 'python-r1': 'python_gen_any_dep',
- }
-
- @staticmethod
- def _prepare_deps(deps: str):
- try:
- deps_str = deps.strip('\"\'').replace('\\$', '$').replace('${PYTHON_USEDEP}', 'pkgcheck_python_usedep')
- return iflatten_instance(DepSet.parse(deps_str, atom), atom)
- except DepsetParseError:
- # if we are unable to parse that dep's string, skip it
- return ()
-
-
- def build_python_gen_any_dep_calls(self, pkg, any_dep_func):
- check_deps = defaultdict(set)
- for var_node in pkg.global_query(bash.var_assign_query):
- name = pkg.node_str(var_node.child_by_field_name('name'))
- if name in {'DEPEND', 'BDEPEND'}:
- for call_node, _ in bash.cmd_query.captures(var_node):
- call_name = pkg.node_str(call_node.child_by_field_name('name'))
- if call_name == any_dep_func and len(call_node.children) > 1:
- check_deps[name].update(self._prepare_deps(
- pkg.node_str(call_node.children[1])))
- return {dep: frozenset(atoms) for dep, atoms in check_deps.items()}
-
- def report_mismatch_check_deps(self, pkg, python_check_deps, has_version_checked_deps, any_dep_func):
- for dep_type in frozenset(python_check_deps.keys()).union(
- has_version_checked_deps.keys()):
- extra = has_version_checked_deps[dep_type] - python_check_deps.get(dep_type, set())
- missing = python_check_deps.get(dep_type, set()) - has_version_checked_deps[dep_type]
- for diff, other, location in (
- (extra, missing, any_dep_func),
- (missing, extra, "python_check_deps"),
- ):
- for dep in diff:
- dep_atom = str(dep.versioned_atom)
- for other_dep in other:
- if dep_atom == str(other_dep.versioned_atom):
- if diff_flags := set(other_dep.use) - set(dep.use):
- yield PythonAnyMismatchedUseHasVersionCheck(pkg=pkg,
- dep_category=dep_type, dep_atom=dep_atom,
- use_flags=diff_flags, location=location)
- break
- else:
- use_flags = {'${PYTHON_USEDEP}'} | set(dep.use) \
- - {'pkgcheck_python_usedep'}
- yield PythonAnyMismatchedDepHasVersionCheck(pkg=pkg,
- dep_category=dep_type, dep_atom=dep_atom,
- use_flags=use_flags, location=location)
-
- @staticmethod
- def _prepare_dep_type(pkg, dep_type: str) -> str:
- if dep_type == 'BDEPEND' not in pkg.eapi.dep_keys:
- return 'DEPEND'
- return dep_type
-
- def check_python_check_deps(self, pkg, func_node, python_check_deps, any_dep_func):
- has_version_checked_deps = defaultdict(set)
- has_version_lines = set()
- for node, _ in bash.cmd_query.captures(func_node):
- call_name = pkg.node_str(node.child_by_field_name('name'))
- if call_name == "has_version":
- lineno, _ = node.start_point
- has_version_lines.add(lineno + 1)
- if dep_mode := self.has_version_default.get(call_name, None):
- dep_mode = self._prepare_dep_type(pkg, dep_mode)
- for arg in node.children[1:]:
- arg_name = pkg.node_str(arg)
- if new_dep_mode := self.has_version_known_flags.get(arg_name, None):
- dep_mode = self._prepare_dep_type(pkg, new_dep_mode)
- else:
- arg_name = arg_name.strip('\"\'')
- if not USE_FLAGS_PYTHON_USEDEP.search(arg_name):
- lineno, _ = arg.start_point
- yield PythonHasVersionMissingPythonUseDep(
- lineno=lineno+1, line=arg_name, pkg=pkg)
- else:
- has_version_checked_deps[dep_mode].update(
- self._prepare_deps(arg_name))
-
- if has_version_lines:
- yield PythonHasVersionUsage(lines=sorted(has_version_lines), pkg=pkg)
-
- yield from self.report_mismatch_check_deps(pkg, python_check_deps, has_version_checked_deps, any_dep_func)
-
- def feed(self, pkg):
- if (python_eclass := get_python_eclass(pkg)) is None:
- return
- any_dep_func = self.eclass_any_dep_func[python_eclass]
- python_check_deps = self.build_python_gen_any_dep_calls(pkg, any_dep_func)
- for func_node, _ in bash.func_query.captures(pkg.tree.root_node):
- func_name = pkg.node_str(func_node.child_by_field_name('name'))
- if func_name == "python_check_deps":
- yield from self.check_python_check_deps(pkg, func_node, python_check_deps, any_dep_func)
diff --git a/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/expected.json b/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/expected.json
new file mode 100644
index 00000000..414608fc
--- /dev/null
+++ b/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/expected.json
@@ -0,0 +1,6 @@
+{"__class__": "PythonHasVersionUsage", "category": "PythonCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "lines": [35, 36]}
+{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/flit_core", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_gen_any_dep"}
+{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/lxml", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_check_deps"}
+{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "dep_category": "DEPEND", "dep_atom": "dev-python/flit_core", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_check_deps"}
+{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "dep_category": "DEPEND", "dep_atom": "dev-python/lxml", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_gen_any_dep"}
+{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "dep_category": "RDEPEND", "dep_atom": "dev-python/lxml", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_gen_any_dep"}
diff --git a/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/fix.patch b/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/fix.patch
new file mode 100644
index 00000000..b53d0dc9
--- /dev/null
+++ b/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/fix.patch
@@ -0,0 +1,28 @@
+diff -dupr python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild fixed/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
+index a70a4d3e..21db4ebf 100644
+--- python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
++++ fixed/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
+@@ -32,8 +32,7 @@ BDEPEND="${PYTHON_DEPS}
+
+ python_check_deps() {
+ use test || return 1
+- has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
+- has_version -r "dev-python/lxml[${PYTHON_USEDEP}]" &&
++ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
+ python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]" &&
+- python_has_version "dev-python/flit_core[${PYTHON_USEDEP}]"
++ python_has_version -d "dev-python/flit_core[${PYTHON_USEDEP}]"
+ }
+diff -dupr python/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild fixed/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
+index 24ebb878..48f4ae11 100644
+--- python/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
++++ fixed/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
+@@ -22,6 +22,6 @@ BDEPEND="${PYTHON_DEPS}
+ "
+
+ python_check_deps() {
+- has_version -b "dev-python/lxml" &&
+- python_has_version "dev-python/gpep517"
++ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
++ python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]"
+ }
diff --git a/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/expected.json b/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/expected.json
new file mode 100644
index 00000000..d41df224
--- /dev/null
+++ b/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/expected.json
@@ -0,0 +1,4 @@
+{"__class__": "PythonAnyMismatchedUseHasVersionCheck", "category": "PythonCheck", "package": "PythonAnyMismatchedUseHasVersionCheck", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/gpep517", "use_flags": ["xml"], "location": "python_check_deps"}
+{"__class__": "PythonAnyMismatchedUseHasVersionCheck", "category": "PythonCheck", "package": "PythonAnyMismatchedUseHasVersionCheck", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/lxml", "use_flags": ["threads"], "location": "python_gen_any_dep"}
+{"__class__": "PythonAnyMismatchedUseHasVersionCheck", "category": "PythonCheck", "package": "PythonAnyMismatchedUseHasVersionCheck", "version": "1", "dep_category": "BDEPEND", "dep_atom": "dev-python/flit", "use_flags": ["threads"], "location": "python_check_deps"}
+{"__class__": "PythonAnyMismatchedUseHasVersionCheck", "category": "PythonCheck", "package": "PythonAnyMismatchedUseHasVersionCheck", "version": "1", "dep_category": "BDEPEND", "dep_atom": "dev-python/gpep517", "use_flags": ["xml"], "location": "python_gen_any_dep"}
diff --git a/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/fix.patch b/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/fix.patch
index e2c61061..2839bffe 100644
--- a/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/fix.patch
+++ b/testdata/data/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/fix.patch
@@ -1,7 +1,7 @@
-diff -dupr a/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild b/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild
+diff -dupr a/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild b/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild
index 52e24cab..f2040c7b 100644
---- python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild
-+++ fixed/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild
+--- python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild
++++ fixed/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild
@@ -17,11 +17,11 @@ DEPEND="${PYTHON_DEPS}"
BDEPEND="${PYTHON_DEPS}
$(python_gen_any_dep '
@@ -16,10 +16,10 @@ index 52e24cab..f2040c7b 100644
+ python_has_version "dev-python/lxml[${PYTHON_USEDEP},threads]" &&
python_has_version "dev-python/gpep517[${PYTHON_USEDEP},xml]"
}
-diff -dupr python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild fixed/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild
+diff -dupr python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild fixed/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild
index d34cef22..f2040c7b 100644
---- python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild
-+++ fixed/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild
+--- python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild
++++ fixed/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild
@@ -16,12 +16,12 @@ SLOT="0"
DEPEND="${PYTHON_DEPS}"
BDEPEND="${PYTHON_DEPS}
diff --git a/testdata/data/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/expected.json b/testdata/data/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/expected.json
new file mode 100644
index 00000000..b2bbf730
--- /dev/null
+++ b/testdata/data/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/expected.json
@@ -0,0 +1,5 @@
+{"__class__": "PythonHasVersionMissingPythonUseDep", "category": "PythonCheck", "package": "PythonHasVersionMissingPythonUseDep", "version": "0", "line": "dev-python/lxml", "lineno": 25}
+{"__class__": "PythonHasVersionMissingPythonUseDep", "category": "PythonCheck", "package": "PythonHasVersionMissingPythonUseDep", "version": "0", "line": "dev-python/gpep517", "lineno": 26}
+{"__class__": "PythonHasVersionUsage", "category": "PythonCheck", "package": "PythonHasVersionMissingPythonUseDep", "version": "0", "lines": [25]}
+{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonCheck", "package": "PythonHasVersionMissingPythonUseDep", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/gpep517", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_check_deps"}
+{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonCheck", "package": "PythonHasVersionMissingPythonUseDep", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/lxml", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_check_deps"}
diff --git a/testdata/data/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/fix.patch b/testdata/data/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/fix.patch
new file mode 100644
index 00000000..e4a24f25
--- /dev/null
+++ b/testdata/data/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/fix.patch
@@ -0,0 +1,13 @@
+diff -dupr a/python/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild fixed/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
+index 24ebb878..48f4ae11 100644
+--- python/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
++++ fixed/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
+@@ -22,6 +22,6 @@ BDEPEND="${PYTHON_DEPS}
+ "
+
+ python_check_deps() {
+- has_version -b "dev-python/lxml" &&
+- python_has_version "dev-python/gpep517"
++ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
++ python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]"
+ }
diff --git a/testdata/data/repos/python/PythonCheck/PythonHasVersionUsage/expected.json b/testdata/data/repos/python/PythonCheck/PythonHasVersionUsage/expected.json
new file mode 100644
index 00000000..3081dc88
--- /dev/null
+++ b/testdata/data/repos/python/PythonCheck/PythonHasVersionUsage/expected.json
@@ -0,0 +1,2 @@
+{"__class__": "PythonHasVersionUsage", "category": "PythonCheck", "package": "PythonHasVersionUsage", "version": "0", "lines": [24]}
+{"__class__": "PythonHasVersionUsage", "category": "PythonCheck", "package": "PythonHasVersionUsage", "version": "1", "lines": [25, 26]}
diff --git a/testdata/data/repos/python/PythonCheck/PythonHasVersionUsage/fix.patch b/testdata/data/repos/python/PythonCheck/PythonHasVersionUsage/fix.patch
new file mode 100644
index 00000000..d6f4923d
--- /dev/null
+++ b/testdata/data/repos/python/PythonCheck/PythonHasVersionUsage/fix.patch
@@ -0,0 +1,52 @@
+diff -dupr python/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild fixed/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild
+index face1460..d8f40dd7 100644
+--- python/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild
++++ fixed/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild
+@@ -21,5 +21,5 @@ BDEPEND="${PYTHON_DEPS}
+ "
+
+ python_check_deps() {
+- has_version -b "dev-python/lxml[${PYTHON_USEDEP}]"
++ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]"
+ }
+diff -dupr python/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild fixed/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild
+index 240f5364..48f4ae11 100644
+--- python/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild
++++ fixed/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild
+@@ -22,6 +22,6 @@ BDEPEND="${PYTHON_DEPS}
+ "
+
+ python_check_deps() {
+- has_version -b "dev-python/lxml[${PYTHON_USEDEP}]" &&
+- has_version -b "dev-python/gpep517[${PYTHON_USEDEP}]"
++ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
++ python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]"
+ }
+diff -dupr a/python/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild b/python/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
+index 24ebb878..48f4ae11 100644
+--- python/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
++++ fixed/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
+@@ -22,6 +22,6 @@ BDEPEND="${PYTHON_DEPS}
+ "
+
+ python_check_deps() {
+- has_version -b "dev-python/lxml" &&
+- python_has_version "dev-python/gpep517"
++ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
++ python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]"
+ }
+diff -dupr python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild fixed/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
+index a70a4d3e..21db4ebf 100644
+--- python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
++++ fixed/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
+@@ -32,8 +32,7 @@ BDEPEND="${PYTHON_DEPS}
+
+ python_check_deps() {
+ use test || return 1
+- has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
+- has_version -r "dev-python/lxml[${PYTHON_USEDEP}]" &&
++ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
+ python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]" &&
+- python_has_version "dev-python/flit_core[${PYTHON_USEDEP}]"
++ python_has_version -d "dev-python/flit_core[${PYTHON_USEDEP}]"
+ }
diff --git a/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/expected.json b/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/expected.json
deleted file mode 100644
index 5bb14866..00000000
--- a/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/expected.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{"__class__": "PythonHasVersionUsage", "category": "PythonWrongUsageCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "lines": [35, 36]}
-{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/flit_core", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_gen_any_dep"}
-{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/lxml", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_check_deps"}
-{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "dep_category": "DEPEND", "dep_atom": "dev-python/flit_core", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_check_deps"}
-{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "dep_category": "DEPEND", "dep_atom": "dev-python/lxml", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_gen_any_dep"}
-{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonAnyMismatchedDepHasVersionCheck", "version": "0", "dep_category": "RDEPEND", "dep_atom": "dev-python/lxml", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_gen_any_dep"}
diff --git a/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/fix.patch b/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/fix.patch
deleted file mode 100644
index 20f5fafd..00000000
--- a/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/fix.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-diff -dupr python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild fixed/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
-index a70a4d3e..21db4ebf 100644
---- python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
-+++ fixed/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
-@@ -32,8 +32,7 @@ BDEPEND="${PYTHON_DEPS}
-
- python_check_deps() {
- use test || return 1
-- has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
-- has_version -r "dev-python/lxml[${PYTHON_USEDEP}]" &&
-+ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
- python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]" &&
-- python_has_version "dev-python/flit_core[${PYTHON_USEDEP}]"
-+ python_has_version -d "dev-python/flit_core[${PYTHON_USEDEP}]"
- }
-diff -dupr python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild fixed/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
-index 24ebb878..48f4ae11 100644
---- python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
-+++ fixed/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
-@@ -22,6 +22,6 @@ BDEPEND="${PYTHON_DEPS}
- "
-
- python_check_deps() {
-- has_version -b "dev-python/lxml" &&
-- python_has_version "dev-python/gpep517"
-+ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
-+ python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]"
- }
diff --git a/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/expected.json b/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/expected.json
deleted file mode 100644
index 1bc290bf..00000000
--- a/testdata/data/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/expected.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{"__class__": "PythonAnyMismatchedUseHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonAnyMismatchedUseHasVersionCheck", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/gpep517", "use_flags": ["xml"], "location": "python_check_deps"}
-{"__class__": "PythonAnyMismatchedUseHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonAnyMismatchedUseHasVersionCheck", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/lxml", "use_flags": ["threads"], "location": "python_gen_any_dep"}
-{"__class__": "PythonAnyMismatchedUseHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonAnyMismatchedUseHasVersionCheck", "version": "1", "dep_category": "BDEPEND", "dep_atom": "dev-python/flit", "use_flags": ["threads"], "location": "python_check_deps"}
-{"__class__": "PythonAnyMismatchedUseHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonAnyMismatchedUseHasVersionCheck", "version": "1", "dep_category": "BDEPEND", "dep_atom": "dev-python/gpep517", "use_flags": ["xml"], "location": "python_gen_any_dep"}
diff --git a/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/expected.json b/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/expected.json
deleted file mode 100644
index 515ee14b..00000000
--- a/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/expected.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{"__class__": "PythonHasVersionMissingPythonUseDep", "category": "PythonWrongUsageCheck", "package": "PythonHasVersionMissingPythonUseDep", "version": "0", "line": "dev-python/lxml", "lineno": 25}
-{"__class__": "PythonHasVersionMissingPythonUseDep", "category": "PythonWrongUsageCheck", "package": "PythonHasVersionMissingPythonUseDep", "version": "0", "line": "dev-python/gpep517", "lineno": 26}
-{"__class__": "PythonHasVersionUsage", "category": "PythonWrongUsageCheck", "package": "PythonHasVersionMissingPythonUseDep", "version": "0", "lines": [25]}
-{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonHasVersionMissingPythonUseDep", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/gpep517", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_check_deps"}
-{"__class__": "PythonAnyMismatchedDepHasVersionCheck", "category": "PythonWrongUsageCheck", "package": "PythonHasVersionMissingPythonUseDep", "version": "0", "dep_category": "BDEPEND", "dep_atom": "dev-python/lxml", "use_flags": ["${PYTHON_USEDEP}"], "location": "python_check_deps"}
diff --git a/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/fix.patch b/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/fix.patch
deleted file mode 100644
index cb34f7bb..00000000
--- a/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/fix.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff -dupr a/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild fixed/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
-index 24ebb878..48f4ae11 100644
---- python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
-+++ fixed/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
-@@ -22,6 +22,6 @@ BDEPEND="${PYTHON_DEPS}
- "
-
- python_check_deps() {
-- has_version -b "dev-python/lxml" &&
-- python_has_version "dev-python/gpep517"
-+ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
-+ python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]"
- }
diff --git a/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/expected.json b/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/expected.json
deleted file mode 100644
index 06234ba8..00000000
--- a/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/expected.json
+++ /dev/null
@@ -1,2 +0,0 @@
-{"__class__": "PythonHasVersionUsage", "category": "PythonWrongUsageCheck", "package": "PythonHasVersionUsage", "version": "0", "lines": [24]}
-{"__class__": "PythonHasVersionUsage", "category": "PythonWrongUsageCheck", "package": "PythonHasVersionUsage", "version": "1", "lines": [25, 26]}
diff --git a/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/fix.patch b/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/fix.patch
deleted file mode 100644
index 2b017c8d..00000000
--- a/testdata/data/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/fix.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-diff -dupr python/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild fixed/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild
-index face1460..d8f40dd7 100644
---- python/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild
-+++ fixed/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild
-@@ -21,5 +21,5 @@ BDEPEND="${PYTHON_DEPS}
- "
-
- python_check_deps() {
-- has_version -b "dev-python/lxml[${PYTHON_USEDEP}]"
-+ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]"
- }
-diff -dupr python/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild fixed/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild
-index 240f5364..48f4ae11 100644
---- python/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild
-+++ fixed/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild
-@@ -22,6 +22,6 @@ BDEPEND="${PYTHON_DEPS}
- "
-
- python_check_deps() {
-- has_version -b "dev-python/lxml[${PYTHON_USEDEP}]" &&
-- has_version -b "dev-python/gpep517[${PYTHON_USEDEP}]"
-+ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
-+ python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]"
- }
-diff -dupr a/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild b/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
-index 24ebb878..48f4ae11 100644
---- python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
-+++ fixed/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
-@@ -22,6 +22,6 @@ BDEPEND="${PYTHON_DEPS}
- "
-
- python_check_deps() {
-- has_version -b "dev-python/lxml" &&
-- python_has_version "dev-python/gpep517"
-+ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
-+ python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]"
- }
-diff -dupr python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild fixed/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
-index a70a4d3e..21db4ebf 100644
---- python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
-+++ fixed/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
-@@ -32,8 +32,7 @@ BDEPEND="${PYTHON_DEPS}
-
- python_check_deps() {
- use test || return 1
-- has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
-- has_version -r "dev-python/lxml[${PYTHON_USEDEP}]" &&
-+ python_has_version "dev-python/lxml[${PYTHON_USEDEP}]" &&
- python_has_version "dev-python/gpep517[${PYTHON_USEDEP}]" &&
-- python_has_version "dev-python/flit_core[${PYTHON_USEDEP}]"
-+ python_has_version -d "dev-python/flit_core[${PYTHON_USEDEP}]"
- }
diff --git a/testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild b/testdata/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
index a70a4d3e..a70a4d3e 100644
--- a/testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
+++ b/testdata/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-0.ebuild
diff --git a/testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-1.ebuild b/testdata/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-1.ebuild
index 2652cf8c..2652cf8c 100644
--- a/testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-1.ebuild
+++ b/testdata/repos/python/PythonCheck/PythonAnyMismatchedDepHasVersionCheck/PythonAnyMismatchedDepHasVersionCheck-1.ebuild
diff --git a/testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild b/testdata/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild
index e1b1c707..e1b1c707 100644
--- a/testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild
+++ b/testdata/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-0.ebuild
diff --git a/testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild b/testdata/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild
index 616bcd95..616bcd95 100644
--- a/testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild
+++ b/testdata/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-1.ebuild
diff --git a/testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-2.ebuild b/testdata/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-2.ebuild
index 0f011b36..0f011b36 100644
--- a/testdata/repos/python/PythonWrongUsageCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-2.ebuild
+++ b/testdata/repos/python/PythonCheck/PythonAnyMismatchedUseHasVersionCheck/PythonAnyMismatchedUseHasVersionCheck-2.ebuild
diff --git a/testdata/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild b/testdata/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
index 24ebb878..24ebb878 100644
--- a/testdata/repos/python/PythonWrongUsageCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
+++ b/testdata/repos/python/PythonCheck/PythonHasVersionMissingPythonUseDep/PythonHasVersionMissingPythonUseDep-0.ebuild
diff --git a/testdata/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild b/testdata/repos/python/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild
index face1460..face1460 100644
--- a/testdata/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild
+++ b/testdata/repos/python/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-0.ebuild
diff --git a/testdata/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild b/testdata/repos/python/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild
index 240f5364..240f5364 100644
--- a/testdata/repos/python/PythonWrongUsageCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild
+++ b/testdata/repos/python/PythonCheck/PythonHasVersionUsage/PythonHasVersionUsage-1.ebuild