From 047ecfad50069aaa55dcbb4261371571de1c58d9 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Moreno Date: Thu, 1 Feb 2024 07:57:44 +0100 Subject: [PATCH 1/2] test: Improve name of mock packages See https://github.com/rpm-software-management/rpmlint/issues/1104 --- test/mock_packages.py | 35 ++++++++++++++++++++++++++++------- test/test_python.py | 24 ++++++++++++------------ 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/test/mock_packages.py b/test/mock_packages.py index 8a2ab32e3..b4e87246c 100644 --- a/test/mock_packages.py +++ b/test/mock_packages.py @@ -1,7 +1,12 @@ -# mock_packages.py from Testing import get_tested_mock_package -PythonSitePackage = get_tested_mock_package( + +######################## +# Python mock packages # +######################## + +# Not valid doc folder in python packages +PythonDocFolderPackage = get_tested_mock_package( files=[ '/usr/lib/python2.7/site-packages/python-mypackage/doc', '/usr/lib/python2.7/site-packages/python-mypackage/docs', @@ -14,7 +19,9 @@ ] ) -PythonModuleMockPackage = get_tested_mock_package( + +# Valid doc folder in python package if it's a python module +PythonDocModulePackage = get_tested_mock_package( files={ '/usr/lib/python2.7/site-packages/python-mypackage/doc/__init__.py': {'create_dirs': True, 'include_dirs': 2}, '/usr/lib/python2.7/site-packages/python-mypackage/docs/__init__.py': {'create_dirs': True, 'include_dirs': 1}, @@ -27,7 +34,9 @@ } ) -PythonDistutilsMockPackage = get_tested_mock_package( + +# Python package with old egginfo file, not folder +PythonEggInfoFileackage = get_tested_mock_package( files={ '/usr/lib/python2.7/site-packages/mydistutilspackage.egg-info': {'content': 'Metadata-Version: 2.1\nName: pythoncheck'}, '/usr/lib/python3.10/site-packages/mydistutilspackage.egg-info': {'content': 'Metadata-Version: 2.1\nName: pythoncheck'}, @@ -36,6 +45,7 @@ } ) + PythonFlitMockPackage = get_tested_mock_package( files={ '/usr/lib/python3.10/site-packages/flit-3.8.0.dist-info/METADATA': { @@ -53,6 +63,7 @@ }, ) + PythonJupyterServerFileidMockPackage = get_tested_mock_package( files={ '/usr/lib/python3.10/site-packages/jupyter_server_fileid-0.9.0.dist-info/METADATA': { @@ -69,6 +80,7 @@ }, ) + PythonJupyterEventsMockPackage = get_tested_mock_package( files={ '/usr/lib/python3.10/site-packages/jupyter_events-0.6.3.dist-info/METADATA': { @@ -102,6 +114,7 @@ }, ) + PythonScikitBuildMockPackage = get_tested_mock_package( files={ '/usr/lib/python3.10/site-packages/scikit_build-0.17.2.dist-info/METADATA': { @@ -120,7 +133,9 @@ }, ) -PythonFlitUpdatedMockPackage = get_tested_mock_package( + +# Python flit package with python3.12dist(foo) requirements (used in Fedora see #1171) +PythonFlitFedoraMockPackage = get_tested_mock_package( files={ '/usr/lib/python3.10/site-packages/flit-3.8.0.dist-info/METADATA': { 'content-path': 'files/python-flit-metadata.txt', @@ -137,6 +152,8 @@ }, ) + +# Python package with old setuptools metadata format, egg-info folder PythonIcecreamPackage = get_tested_mock_package( files={ '/usr/lib/python3.10/site-packages/icecream-2.1.3-py3.10.egg-info/requires.txt': { @@ -160,7 +177,9 @@ ) -PythonBlinkerMockPackage = get_tested_mock_package( +# Python package with multiple pyc for different python versions in the same +# sitelib +PythonMultiplePYCMockPackage = get_tested_mock_package( files=[ '/usr/lib/python3.9/site-packages/blinker/__pycache__/base.cpython-310.pyc', '/usr/lib/python3.9/site-packages/blinker/__pycache__/base.cpython-39.opt-1.pyc', @@ -177,7 +196,9 @@ ] ) -PythonSiteBlinkerMockPackage = get_tested_mock_package( + +# Python package with pyc files but just the correct version +PythonSinglePYCMockPackage = get_tested_mock_package( files=[ '/usr/lib/python3.9/site-packages/blinker/__pycache__/base.cpython-39.opt-1.pyc', '/usr/lib/python3.9/site-packages/blinker/__pycache__/base.cpython-39.pyc', diff --git a/test/test_python.py b/test/test_python.py index 700844e92..c60640047 100644 --- a/test/test_python.py +++ b/test/test_python.py @@ -1,15 +1,15 @@ from mock_packages import ( - PythonBlinkerMockPackage, - PythonDistutilsMockPackage, + PythonDocFolderPackage, + PythonDocModulePackage, + PythonEggInfoFileackage, + PythonFlitFedoraMockPackage, PythonFlitMockPackage, - PythonFlitUpdatedMockPackage, PythonIcecreamPackage, PythonJupyterEventsMockPackage, PythonJupyterServerFileidMockPackage, - PythonModuleMockPackage, + PythonMultiplePYCMockPackage, PythonScikitBuildMockPackage, - PythonSiteBlinkerMockPackage, - PythonSitePackage, + PythonSinglePYCMockPackage, ) import pytest from rpmlint.checks.PythonCheck import PythonCheck @@ -38,7 +38,7 @@ def test(pythoncheck): yield test -@pytest.mark.parametrize('package', [PythonSitePackage]) +@pytest.mark.parametrize('package', [PythonDocFolderPackage]) def test_python_doc_in_package(package, test, output): test.check(package) out = output.print_results(output.results) @@ -52,7 +52,7 @@ def test_python_doc_in_package(package, test, output): assert 'W: python-doc-in-package /usr/lib64/python3.10/site-packages/python-mypackage/docs' in out -@pytest.mark.parametrize('package', [PythonModuleMockPackage]) +@pytest.mark.parametrize('package', [PythonDocModulePackage]) def test_python_doc_module_in_package(package, test, output): test.check(package) out = output.print_results(output.results) @@ -66,7 +66,7 @@ def test_python_doc_module_in_package(package, test, output): assert 'W: python-doc-in-package /usr/lib64/python3.10/site-packages/python-mypackage/docs' not in out -@pytest.mark.parametrize('package', [PythonDistutilsMockPackage]) +@pytest.mark.parametrize('package', [PythonEggInfoFileackage]) def test_python_distutils_egg_info(package, test, output): test.check(package) out = output.print_results(output.results) @@ -147,7 +147,7 @@ def test_python_tests_in_site_packages(package, test, output): PythonJupyterServerFileidMockPackage, PythonJupyterEventsMockPackage, PythonScikitBuildMockPackage, - PythonFlitUpdatedMockPackage,]) + PythonFlitFedoraMockPackage,]) def test_python_dependencies_metadata(package, test, output): test.check(package) out = output.print_results(output.results) @@ -257,14 +257,14 @@ def test_python_dependencies_leftover(package, test, output): assert 'W: python-leftover-require' in out -@pytest.mark.parametrize('package', [PythonBlinkerMockPackage]) +@pytest.mark.parametrize('package', [PythonMultiplePYCMockPackage]) def test_python_pyc_multiple_versions(package, test, output): test.check(package) out = output.print_results(output.results) assert 'W: python-pyc-multiple-versions expected: 310' in out -@pytest.mark.parametrize('package', [PythonSiteBlinkerMockPackage]) +@pytest.mark.parametrize('package', [PythonSinglePYCMockPackage]) def test_python_pyc_single_version(package, test, output): test.check(package) out = output.print_results(output.results) From f4d0ed106349d7034b26263a96947937562ea197 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Moreno Date: Thu, 1 Feb 2024 10:10:22 +0100 Subject: [PATCH 2/2] test: Lazy load mock packages This patch add the ability to lazy load the mock packages annd also a way to copy mock packages to just modify some of the package data. See https://github.com/rpm-software-management/rpmlint/issues/1104 --- test/Testing.py | 46 +++++++++++++++++++++++- test/mock_packages.py | 63 +++++++++++++++++++++++++++++++++ test/test_python.py | 82 +++++-------------------------------------- 3 files changed, 116 insertions(+), 75 deletions(-) diff --git a/test/Testing.py b/test/Testing.py index 18cc0c93a..e386f181d 100644 --- a/test/Testing.py +++ b/test/Testing.py @@ -62,7 +62,51 @@ def get_tested_spec_package(name): return FakePkg(candidates[0]) -def get_tested_mock_package(files=None, header=None, name='mockPkg'): +class LazyMock: + """ + Class to store mock package definition and create the actual mock package + when needed, when some internal attribute or method is requested. + """ + + def __init__(self, files, header, name): + self._lazy_pkg = None + self._lazy_files = files + self._lazy_header = header + self._lazy_name = name + + @property + def _fake_pkg(self): + if not self._lazy_pkg: + self._lazy_pkg = get_tested_mock_package(self._lazy_files, + self._lazy_header, + self._lazy_name) + return self._lazy_pkg + + def clone(self, files=None, header=None, name=None): + """ + Copies this LazyMock modifying some properties + """ + + if files is None: + files = self._lazy_files + if header is None: + header = self._lazy_header + if name is None: + name = self._lazy_name + + return LazyMock(files, header, name) + + def __getitem__(self, key): + return self._fake_pkg.__getitem__(key) + + def __getattr__(self, name): + return getattr(self._fake_pkg, name) + + +def get_tested_mock_package(files=None, header=None, name='mockPkg', lazyload=False): + if lazyload: + return LazyMock(files, header, name) + mockPkg = FakePkg(name) if files is not None: if isinstance(files, dict): diff --git a/test/mock_packages.py b/test/mock_packages.py index b4e87246c..9d3fbac85 100644 --- a/test/mock_packages.py +++ b/test/mock_packages.py @@ -7,6 +7,7 @@ # Not valid doc folder in python packages PythonDocFolderPackage = get_tested_mock_package( + lazyload=True, files=[ '/usr/lib/python2.7/site-packages/python-mypackage/doc', '/usr/lib/python2.7/site-packages/python-mypackage/docs', @@ -22,6 +23,7 @@ # Valid doc folder in python package if it's a python module PythonDocModulePackage = get_tested_mock_package( + lazyload=True, files={ '/usr/lib/python2.7/site-packages/python-mypackage/doc/__init__.py': {'create_dirs': True, 'include_dirs': 2}, '/usr/lib/python2.7/site-packages/python-mypackage/docs/__init__.py': {'create_dirs': True, 'include_dirs': 1}, @@ -37,6 +39,7 @@ # Python package with old egginfo file, not folder PythonEggInfoFileackage = get_tested_mock_package( + lazyload=True, files={ '/usr/lib/python2.7/site-packages/mydistutilspackage.egg-info': {'content': 'Metadata-Version: 2.1\nName: pythoncheck'}, '/usr/lib/python3.10/site-packages/mydistutilspackage.egg-info': {'content': 'Metadata-Version: 2.1\nName: pythoncheck'}, @@ -47,6 +50,7 @@ PythonFlitMockPackage = get_tested_mock_package( + lazyload=True, files={ '/usr/lib/python3.10/site-packages/flit-3.8.0.dist-info/METADATA': { 'content-path': 'files/python-flit-metadata.txt', @@ -64,7 +68,34 @@ ) +# Python package with missing require +PythonFlitMissingRequirePackage = PythonFlitMockPackage.clone( + header={ + 'requires': [ + 'python3-flit-core', + 'python3-requests', + 'python3-tomli-w', + ], + }, +) + + +# Python package with missing require +PythonFlitLeftoverRequirePackage = PythonFlitMockPackage.clone( + header={ + 'requires': [ + 'python3-docutils', + 'python3-flit-core', + 'python3-poetry', + 'python3-requests', + 'python3-tomli-w', + ], + }, +) + + PythonJupyterServerFileidMockPackage = get_tested_mock_package( + lazyload=True, files={ '/usr/lib/python3.10/site-packages/jupyter_server_fileid-0.9.0.dist-info/METADATA': { 'content-path': 'files/python-jupyter_server_fileid-metadata.txt', @@ -82,6 +113,7 @@ PythonJupyterEventsMockPackage = get_tested_mock_package( + lazyload=True, files={ '/usr/lib/python3.10/site-packages/jupyter_events-0.6.3.dist-info/METADATA': { 'content-path': 'files/python-jupyter-events-metadata.txt', @@ -116,6 +148,7 @@ PythonScikitBuildMockPackage = get_tested_mock_package( + lazyload=True, files={ '/usr/lib/python3.10/site-packages/scikit_build-0.17.2.dist-info/METADATA': { 'content-path': 'files/python-scikit_build-metadata.txt', @@ -136,6 +169,7 @@ # Python flit package with python3.12dist(foo) requirements (used in Fedora see #1171) PythonFlitFedoraMockPackage = get_tested_mock_package( + lazyload=True, files={ '/usr/lib/python3.10/site-packages/flit-3.8.0.dist-info/METADATA': { 'content-path': 'files/python-flit-metadata.txt', @@ -155,6 +189,7 @@ # Python package with old setuptools metadata format, egg-info folder PythonIcecreamPackage = get_tested_mock_package( + lazyload=True, files={ '/usr/lib/python3.10/site-packages/icecream-2.1.3-py3.10.egg-info/requires.txt': { 'content': """ @@ -177,9 +212,36 @@ ) +# Python package with missing require +PythonIcecreamMissingRequirePackage = PythonIcecreamPackage.clone( + header={ + 'requires': [ + 'asttokens>=2.0.1', + 'executing>=0.3.1', + 'pygments>=2.2.0', + ], + }, +) + + +# Python package with leftover require +PythonIcecreamLeftoverRequirePackage = PythonIcecreamPackage.clone( + header={ + 'requires': [ + 'python3-asttokens >= 2.0.1', + 'python3-colorama >= 0.3.9', + 'python3-executing >= 0.3.1', + 'python3-poetry', + 'python3-pygments >= 2.2.0', + ], + }, +) + + # Python package with multiple pyc for different python versions in the same # sitelib PythonMultiplePYCMockPackage = get_tested_mock_package( + lazyload=True, files=[ '/usr/lib/python3.9/site-packages/blinker/__pycache__/base.cpython-310.pyc', '/usr/lib/python3.9/site-packages/blinker/__pycache__/base.cpython-39.opt-1.pyc', @@ -199,6 +261,7 @@ # Python package with pyc files but just the correct version PythonSinglePYCMockPackage = get_tested_mock_package( + lazyload=True, files=[ '/usr/lib/python3.9/site-packages/blinker/__pycache__/base.cpython-39.opt-1.pyc', '/usr/lib/python3.9/site-packages/blinker/__pycache__/base.cpython-39.pyc', diff --git a/test/test_python.py b/test/test_python.py index c60640047..fa9e6cf44 100644 --- a/test/test_python.py +++ b/test/test_python.py @@ -3,7 +3,11 @@ PythonDocModulePackage, PythonEggInfoFileackage, PythonFlitFedoraMockPackage, + PythonFlitLeftoverRequirePackage, + PythonFlitMissingRequirePackage, PythonFlitMockPackage, + PythonIcecreamLeftoverRequirePackage, + PythonIcecreamMissingRequirePackage, PythonIcecreamPackage, PythonJupyterEventsMockPackage, PythonJupyterServerFileidMockPackage, @@ -163,47 +167,14 @@ def test_python_dependencies_requires(package, test, output): assert 'W: python-leftover-require' not in out -@pytest.mark.parametrize('package', [get_tested_mock_package( - files={ - '/usr/lib/python3.10/site-packages/icecream-2.1.3-py3.10.egg-info/requires.txt': { - 'content': """ -asttokens>=2.0.1 -colorama>=0.3.9 -executing>=0.3.1 -pygments>=2.2.0 -""", - 'create_dirs': True - }, - }, - header={ - 'requires': [ - 'asttokens>=2.0.1', - 'executing>=0.3.1', - 'pygments>=2.2.0', - ], - }, -)]) +@pytest.mark.parametrize('package', [PythonIcecreamMissingRequirePackage]) def test_python_dependencies_missing_requires(package, test, output): test.check(package) out = output.print_results(output.results) assert 'W: python-missing-require' in out -@pytest.mark.parametrize('package', [get_tested_mock_package( - files={ - '/usr/lib/python3.10/site-packages/flit-3.8.0.dist-info/METADATA': { - 'content-path': 'files/python-flit-metadata.txt', - 'create_dirs': True - }, - }, - header={ - 'requires': [ - 'python3-flit-core', - 'python3-requests', - 'python3-tomli-w', - ], - }, -)]) +@pytest.mark.parametrize('package', [PythonFlitMissingRequirePackage]) def test_python_dependencies_missing_metadata(package, test, output): test.check(package) out = output.print_results(output.results) @@ -211,45 +182,8 @@ def test_python_dependencies_missing_metadata(package, test, output): @pytest.mark.parametrize('package', [ - get_tested_mock_package( - files={ - '/usr/lib/python3.10/site-packages/icecream-2.1.3-py3.10.egg-info/requires.txt': { - 'content': """ -asttokens>=2.0.1 -colorama>=0.3.9 -executing>=0.3.1 -pygments>=2.2.0 -""", - 'create_dirs': True - }, - }, - header={ - 'requires': [ - 'python3-asttokens >= 2.0.1', - 'python3-colorama >= 0.3.9', - 'python3-executing >= 0.3.1', - 'python3-poetry', - 'python3-pygments >= 2.2.0', - ], - }, - ), - get_tested_mock_package( - files={ - '/usr/lib/python3.10/site-packages/flit-3.8.0.dist-info/METADATA': { - 'content-path': 'files/python-flit-metadata.txt', - 'create_dirs': True - }, - }, - header={ - 'requires': [ - 'python3-docutils', - 'python3-flit-core', - 'python3-poetry', - 'python3-requests', - 'python3-tomli-w', - ], - }, - ), + PythonIcecreamLeftoverRequirePackage, + PythonFlitLeftoverRequirePackage, ]) def test_python_dependencies_leftover(package, test, output): test.check(package)