Add python check (#955)
* Add PythonCheck (#423) This adds a Python specific check that performs 2 tasks: 1) Verify the egg-info is folder (setuptools based) and not file based (distutils style) 2) Check for Python specific forbidden dirs and output various warnings and errors about them. * PythonCheck: remove src-in-package check * PythonCheck: extend test cases to /usr/lib64 * PythonCheck: ignore tests in -test{,s} packages. * Update rpmlint/descriptions/PythonCheck.toml Co-authored-by: Miro Hrončok <miro@hroncok.cz> * PythonCheck: update to the latest codebase * Rename test file to be able to use get_tested_package * Improve PythonCheck error descrpitions Co-authored-by: Miro Hrončok <miro@hroncok.cz> * PythonCheck: juse endswith with tuple instead of or * PythonCheck: Use pathlib.Path instead of os.path * PythonCheck: recommend dist-info instead of egg-info * PythonCheck: compile re at module level * fixup! PythonCheck: Use pathlib.Path instead of os.path * PythonCheck: Update test binary packages These binary packages are generated from the following source spec: https://build.opensuse.org/package/show/devel:openSUSE:Factory:rpmlint:tests/pythoncheck * PythonCheck: Convert python-tests-in-package to Error * PythonCheck: Do not warn on python modules named doc * PythonCheck: Improve python-tests-in-package descriptions Co-authored-by: Miro Hrončok <miro@hroncok.cz> * PythonCheck: Improve python-doc-in-package descriptions Co-authored-by: Miro Hrončok <miro@hroncok.cz> * PythonCheck: Improve python-egg-info-distutils-style descriptions Co-authored-by: Miro Hrončok <miro@hroncok.cz> Co-authored-by: Johannes Grassler <johannes.grassler@suse.com> Co-authored-by: Johannes Grassler <jgr-github@btw23.de> Co-authored-by: Miro Hrončok <miro@hroncok.cz>
This commit is contained in:
parent
52f85dfedd
commit
3b98cb263a
|
@ -0,0 +1,76 @@
|
|||
from pathlib import Path
|
||||
import re
|
||||
|
||||
from rpmlint.checks.AbstractCheck import AbstractFilesCheck
|
||||
|
||||
# Warning messages
|
||||
WARNS = {
|
||||
'doc': 'python-doc-in-package',
|
||||
}
|
||||
|
||||
# Error messages
|
||||
ERRS = {
|
||||
'egg-distutils': 'python-egg-info-distutils-style',
|
||||
'tests': 'python-tests-in-site-packages',
|
||||
'doc': 'python-doc-in-site-packages',
|
||||
'src': 'python-src-in-site-packages',
|
||||
'tests-package': 'python-tests-in-package',
|
||||
}
|
||||
|
||||
SITELIB_RE = '/usr/lib[^/]*/python[^/]*/site-packages'
|
||||
|
||||
# Paths that shouldn't be in any packages, ever, because they clobber global
|
||||
# name space.
|
||||
ERR_PATHS = [
|
||||
(re.compile(f'{SITELIB_RE}/tests?$'), 'tests'),
|
||||
(re.compile(f'{SITELIB_RE}/docs?$'), 'doc'),
|
||||
(re.compile(f'{SITELIB_RE}/src$'), 'src'),
|
||||
(re.compile(f'{SITELIB_RE}/[^/]+/tests?$'), 'tests-package'),
|
||||
]
|
||||
|
||||
# Paths that shouldn't be in any packages, but might need to be under
|
||||
# sufficiently special circumstances.
|
||||
WARN_PATHS = [
|
||||
(re.compile(f'{SITELIB_RE}/[^/]+/docs?$'), 'doc'),
|
||||
]
|
||||
|
||||
|
||||
class PythonCheck(AbstractFilesCheck):
|
||||
def __init__(self, config, output):
|
||||
super().__init__(config, output, r'.*')
|
||||
|
||||
def check_file(self, pkg, filename):
|
||||
egg_info_re = re.compile('.*egg-info$')
|
||||
|
||||
if egg_info_re.match(filename):
|
||||
self.check_egginfo(pkg, filename)
|
||||
|
||||
for path_re, key in WARN_PATHS:
|
||||
if path_re.match(filename):
|
||||
if key == 'doc':
|
||||
# Check for __init__.py file inside doc, maybe this is a
|
||||
# module, not documentation
|
||||
module_file = f'{filename}/__init__.py'
|
||||
if module_file in pkg.files.keys():
|
||||
continue
|
||||
self.output.add_info('W', pkg, WARNS[key], filename)
|
||||
|
||||
for path_re, key in ERR_PATHS:
|
||||
if path_re.match(filename):
|
||||
if key == 'tests-package':
|
||||
# Ignore "-test" and "-tests" packages since these are
|
||||
# supposed to contain tests.
|
||||
if pkg.name.endswith(('test', 'tests')):
|
||||
continue
|
||||
self.output.add_info('E', pkg, ERRS[key], filename)
|
||||
|
||||
def check_egginfo(self, pkg, filename):
|
||||
"""
|
||||
Check type of egg-info metadata and check Requires against egg-info
|
||||
metadata if applicable.
|
||||
"""
|
||||
|
||||
filepath = Path(pkg.dir_name() or '/', filename.lstrip('/'))
|
||||
# Check for (deprecated) distutils style metadata.
|
||||
if filepath.is_file():
|
||||
self.output.add_info('E', pkg, ERRS['egg-distutils'], filename)
|
|
@ -20,6 +20,7 @@ Checks = [
|
|||
"MixedOwnershipCheck",
|
||||
"PkgConfigCheck",
|
||||
"PostCheck",
|
||||
"PythonCheck",
|
||||
"SignatureCheck",
|
||||
"SourceCheck",
|
||||
"SpecCheck",
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
python-tests-in-package="""
|
||||
test/ or tests/ directory in Python package directory. Tests in %{python_sitelib}/<pkgname> should be packaged in a separate test or tests subpackage or not packaged."""
|
||||
python-doc-in-package="""
|
||||
doc/ or docs/ directory in Python package directory. Documentation should go into %{docdir}, not %{python_sitelib}/<pkgname>"""
|
||||
python-egg-info-distutils-style="""
|
||||
The Python package's egg-info is a distutils style file.
|
||||
Please update to dist-info standardized core metadata.
|
||||
"""
|
||||
python-tests-in-site-packages="""
|
||||
test/ or tests/ directory in %{python_sitelib}. This should never happen since
|
||||
this is a global name space not owned by any particular package.
|
||||
"""
|
||||
python-doc-in-site-packages="""
|
||||
doc/ or docs directory installed to %{python_sitelib}. This should never happen
|
||||
since this is a global name space not owned by any particular package.
|
||||
"""
|
||||
python-src-in-site-packages="""
|
||||
src/ directory installed to %{python_sitelib}. This should never happen
|
||||
since this is a global name space not owned by any particular package.
|
||||
"""
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -48,6 +48,7 @@ basic_tests = [
|
|||
'MixedOwnershipCheck',
|
||||
'PkgConfigCheck',
|
||||
'PostCheck',
|
||||
'PythonCheck',
|
||||
'SignatureCheck',
|
||||
'SourceCheck',
|
||||
'SpecCheck',
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
import pytest
|
||||
from rpmlint.checks.PythonCheck import PythonCheck
|
||||
from rpmlint.filter import Filter
|
||||
|
||||
from Testing import CONFIG, get_tested_package
|
||||
|
||||
|
||||
@pytest.fixture(scope='function', autouse=True)
|
||||
def pythoncheck():
|
||||
CONFIG.info = True
|
||||
output = Filter(CONFIG)
|
||||
test = PythonCheck(CONFIG, output)
|
||||
return output, test
|
||||
|
||||
|
||||
@pytest.mark.parametrize('package', ['binary/pythoncheck-python-doc-in-package'])
|
||||
def test_python_doc_in_package(tmpdir, package, pythoncheck):
|
||||
output, test = pythoncheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'W: python-doc-in-package /usr/lib/python2.7/site-packages/python-mypackage/doc' in out
|
||||
assert 'W: python-doc-in-package /usr/lib/python2.7/site-packages/python-mypackage/docs' in out
|
||||
assert 'W: python-doc-in-package /usr/lib/python3.10/site-packages/python-mypackage/doc' in out
|
||||
assert 'W: python-doc-in-package /usr/lib/python3.10/site-packages/python-mypackage/docs' in out
|
||||
assert 'W: python-doc-in-package /usr/lib64/python2.7/site-packages/python-mypackage/doc' in out
|
||||
assert 'W: python-doc-in-package /usr/lib64/python2.7/site-packages/python-mypackage/docs' in out
|
||||
assert 'W: python-doc-in-package /usr/lib64/python3.10/site-packages/python-mypackage/doc' in out
|
||||
assert 'W: python-doc-in-package /usr/lib64/python3.10/site-packages/python-mypackage/docs' in out
|
||||
|
||||
|
||||
@pytest.mark.parametrize('package', ['binary/pythoncheck-python-doc-module-in-package'])
|
||||
def test_python_doc_module_in_package(tmpdir, package, pythoncheck):
|
||||
output, test = pythoncheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'W: python-doc-in-package /usr/lib/python2.7/site-packages/python-mypackage/doc' not in out
|
||||
assert 'W: python-doc-in-package /usr/lib/python2.7/site-packages/python-mypackage/docs' not in out
|
||||
assert 'W: python-doc-in-package /usr/lib/python3.10/site-packages/python-mypackage/doc' not in out
|
||||
assert 'W: python-doc-in-package /usr/lib/python3.10/site-packages/python-mypackage/docs' not in out
|
||||
assert 'W: python-doc-in-package /usr/lib64/python2.7/site-packages/python-mypackage/doc' not in out
|
||||
assert 'W: python-doc-in-package /usr/lib64/python2.7/site-packages/python-mypackage/docs' not in out
|
||||
assert 'W: python-doc-in-package /usr/lib64/python3.10/site-packages/python-mypackage/doc' not in out
|
||||
assert 'W: python-doc-in-package /usr/lib64/python3.10/site-packages/python-mypackage/docs' not in out
|
||||
|
||||
|
||||
@pytest.mark.parametrize('package', ['binary/pythoncheck-python-tests-in-package2'])
|
||||
def test_python_tests_in_package(tmpdir, package, pythoncheck):
|
||||
output, test = pythoncheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'E: python-tests-in-package /usr/lib/python2.7/site-packages/python-mypackage/test' in out
|
||||
assert 'E: python-tests-in-package /usr/lib/python2.7/site-packages/python-mypackage/tests' in out
|
||||
assert 'E: python-tests-in-package /usr/lib/python3.10/site-packages/python-mypackage/test' in out
|
||||
assert 'E: python-tests-in-package /usr/lib/python3.10/site-packages/python-mypackage/tests' in out
|
||||
assert 'E: python-tests-in-package /usr/lib64/python2.7/site-packages/python-mypackage/test' in out
|
||||
assert 'E: python-tests-in-package /usr/lib64/python2.7/site-packages/python-mypackage/tests' in out
|
||||
assert 'E: python-tests-in-package /usr/lib64/python3.10/site-packages/python-mypackage/test' in out
|
||||
assert 'E: python-tests-in-package /usr/lib64/python3.10/site-packages/python-mypackage/tests' in out
|
||||
|
||||
|
||||
@pytest.mark.parametrize('package', ['binary/pythoncheck-python-tests-in-package-test'])
|
||||
def test_python_tests_in_test_package(tmpdir, package, pythoncheck):
|
||||
output, test = pythoncheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'E: python-tests-in-package /usr/lib/python2.7/site-packages/python-mypackage/test' not in out
|
||||
assert 'E: python-tests-in-package /usr/lib/python2.7/site-packages/python-mypackage/tests' not in out
|
||||
assert 'E: python-tests-in-package /usr/lib/python3.10/site-packages/python-mypackage/test' not in out
|
||||
assert 'E: python-tests-in-package /usr/lib/python3.10/site-packages/python-mypackage/tests' not in out
|
||||
assert 'E: python-tests-in-package /usr/lib64/python2.7/site-packages/python-mypackage/test' not in out
|
||||
assert 'E: python-tests-in-package /usr/lib64/python2.7/site-packages/python-mypackage/tests' not in out
|
||||
assert 'E: python-tests-in-package /usr/lib64/python3.10/site-packages/python-mypackage/test' not in out
|
||||
assert 'E: python-tests-in-package /usr/lib64/python3.10/site-packages/python-mypackage/tests' not in out
|
||||
|
||||
|
||||
@pytest.mark.parametrize('package', ['binary/pythoncheck-python-egg-info-distutils-style'])
|
||||
def test_python_distutils_egg_info(tmpdir, package, pythoncheck):
|
||||
output, test = pythoncheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'E: python-egg-info-distutils-style /usr/lib/python2.7/site-packages/mydistutilspackage.egg-info' in out
|
||||
assert 'E: python-egg-info-distutils-style /usr/lib/python3.10/site-packages/mydistutilspackage.egg-info' in out
|
||||
assert 'E: python-egg-info-distutils-style /usr/lib64/python2.7/site-packages/mydistutilspackage.egg-info' in out
|
||||
assert 'E: python-egg-info-distutils-style /usr/lib64/python3.10/site-packages/mydistutilspackage.egg-info' in out
|
||||
|
||||
|
||||
@pytest.mark.parametrize('package', ['binary/pythoncheck-python-doc-in-site-packages'])
|
||||
def test_python_doc_in_site_packages(tmpdir, package, pythoncheck):
|
||||
output, test = pythoncheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'E: python-doc-in-site-packages /usr/lib/python2.7/site-packages/doc' in out
|
||||
assert 'E: python-doc-in-site-packages /usr/lib/python2.7/site-packages/docs' in out
|
||||
assert 'E: python-doc-in-site-packages /usr/lib/python3.10/site-packages/doc' in out
|
||||
assert 'E: python-doc-in-site-packages /usr/lib/python3.10/site-packages/docs' in out
|
||||
assert 'E: python-doc-in-site-packages /usr/lib64/python2.7/site-packages/doc' in out
|
||||
assert 'E: python-doc-in-site-packages /usr/lib64/python2.7/site-packages/docs' in out
|
||||
assert 'E: python-doc-in-site-packages /usr/lib64/python3.10/site-packages/doc' in out
|
||||
assert 'E: python-doc-in-site-packages /usr/lib64/python3.10/site-packages/docs' in out
|
||||
|
||||
|
||||
@pytest.mark.parametrize('package', ['binary/pythoncheck-python-src-in-site-packages'])
|
||||
def test_python_src_in_site_packages(tmpdir, package, pythoncheck):
|
||||
output, test = pythoncheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'E: python-src-in-site-packages /usr/lib/python2.7/site-packages/src' in out
|
||||
assert 'E: python-src-in-site-packages /usr/lib/python3.10/site-packages/src' in out
|
||||
assert 'E: python-src-in-site-packages /usr/lib64/python2.7/site-packages/src' in out
|
||||
assert 'E: python-src-in-site-packages /usr/lib64/python3.10/site-packages/src' in out
|
||||
|
||||
|
||||
@pytest.mark.parametrize('package', ['binary/pythoncheck-python-tests-in-site-packages'])
|
||||
def test_python_tests_in_site_packages(tmpdir, package, pythoncheck):
|
||||
output, test = pythoncheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'E: python-tests-in-site-packages /usr/lib/python2.7/site-packages/test' in out
|
||||
assert 'E: python-tests-in-site-packages /usr/lib/python2.7/site-packages/tests' in out
|
||||
assert 'E: python-tests-in-site-packages /usr/lib/python3.10/site-packages/test' in out
|
||||
assert 'E: python-tests-in-site-packages /usr/lib/python3.10/site-packages/tests' in out
|
||||
assert 'E: python-tests-in-site-packages /usr/lib64/python2.7/site-packages/test' in out
|
||||
assert 'E: python-tests-in-site-packages /usr/lib64/python2.7/site-packages/tests' in out
|
||||
assert 'E: python-tests-in-site-packages /usr/lib64/python3.10/site-packages/test' in out
|
||||
assert 'E: python-tests-in-site-packages /usr/lib64/python3.10/site-packages/tests' in out
|
Loading…
Reference in New Issue