From 57c1e4916a809a2cc0d938ad933cc95a8aaf120e Mon Sep 17 00:00:00 2001 From: starlet-dx <15929766099@163.com> Date: Fri, 13 May 2022 10:59:03 +0800 Subject: [PATCH] Resolve the compilation failure in the check phase --- 0001-upgrade-pytest-version.patch | 2 +- pytest-6.1-and-7.patch | 218 ++++++++++++++++++++++++++++++ pytest-relaxed-pr10.patch | 175 ++++++++++++++++++++++++ python-pytest-relaxed.spec | 7 +- 4 files changed, 400 insertions(+), 2 deletions(-) create mode 100644 pytest-6.1-and-7.patch create mode 100644 pytest-relaxed-pr10.patch diff --git a/0001-upgrade-pytest-version.patch b/0001-upgrade-pytest-version.patch index 527da8e..0decf1c 100644 --- a/0001-upgrade-pytest-version.patch +++ b/0001-upgrade-pytest-version.patch @@ -16,7 +16,7 @@ index d3af51b..44d9393 100644 "pytest11": ["relaxed = pytest_relaxed.plugin"] }, - install_requires=["pytest>=3,<5", "six>=1,<2", "decorator>=4,<5"], -+ install_requires=["pytest>=3,<6", "six>=1,<2", "decorator>=4,<5"], ++ install_requires=["pytest>=3,<7", "six>=1,<2", "decorator>=4,<6"], classifiers=[ "Development Status :: 5 - Production/Stable", "Framework :: Pytest", diff --git a/pytest-6.1-and-7.patch b/pytest-6.1-and-7.patch new file mode 100644 index 0000000..d7a9e32 --- /dev/null +++ b/pytest-6.1-and-7.patch @@ -0,0 +1,218 @@ +Index: pytest-relaxed-1.1.5/pytest_relaxed/classes.py +=================================================================== +--- pytest-relaxed-1.1.5.orig/pytest_relaxed/classes.py ++++ pytest-relaxed-1.1.5/pytest_relaxed/classes.py +@@ -4,7 +4,7 @@ import types + import six + + from pytest import __version__ as pytest_version +-from pytest import Class, Instance, Module ++from pytest import Class, Module + + # NOTE: don't see any other way to get access to pytest innards besides using + # the underscored name :( +@@ -12,6 +12,13 @@ from _pytest.python import PyCollector + + pytest_version_info = tuple(map(int, pytest_version.split(".")[:3])) + ++# https://docs.pytest.org/en/latest/deprecations.html#the-pytest-instance-collector ++# The pytest.Instance collector type has been removed in Pytest 7.0 ++if pytest_version_info < (7, 0, 0): ++ from pytest import Instance ++else: ++ from pathlib import Path ++ Instance = object + + # NOTE: these are defined here for reuse by both pytest's own machinery and our + # internal bits. +@@ -22,6 +29,47 @@ def istestclass(name): + def istestfunction(name): + return not (name.startswith("_") or name in ("setup", "teardown")) + ++def _get_obj_rec(obj, parent_obj): ++ # Obtain parent attributes, etc not found on our obj (serves as both a ++ # useful identifier of "stuff added to an outer class" and a way of ++ # ensuring that we can override such attrs), and set them on obj ++ delta = set(dir(parent_obj)).difference(set(dir(obj))) ++ for name in delta: ++ value = getattr(parent_obj, name) ++ # Pytest's pytestmark attributes always get skipped, we don't want ++ # to spread that around where it's not wanted. (Besides, it can ++ # cause a lot of collection level warnings.) ++ if name == "pytestmark": ++ continue ++ # Classes get skipped; they'd always just be other 'inner' classes ++ # that we don't want to copy elsewhere. ++ if isinstance(value, six.class_types): ++ continue ++ # Methods may get skipped, or not, depending: ++ if isinstance(value, types.MethodType): ++ # If they look like tests, they get skipped; don't want to copy ++ # tests around! ++ if istestfunction(name): ++ continue ++ # Non-test == they're probably lifecycle methods ++ # (setup/teardown) or helpers (_do_thing). Rebind them to the ++ # target instance, otherwise the 'self' in the setup/helper is ++ # not the same 'self' as that in the actual test method it runs ++ # around or within! ++ # TODO: arguably, all setup or helper methods should become ++ # autouse class fixtures (see e.g. pytest docs under 'xunit ++ # setup on steroids') ++ func = six.get_method_function(value) ++ setattr(obj, name, six.create_bound_method(func, obj)) ++ continue ++ # Same as above but for Pytest 7 which does ++ # collect methods as functions, and without the six wrapper. ++ if isinstance(value, types.FunctionType) and istestfunction(name): ++ continue ++ # Anything else should be some data-type attribute, which is copied ++ # verbatim / by-value. ++ setattr(obj, name, value) ++ return obj + + # All other classes in here currently inherit from PyCollector, and it is what + # defines the default istestfunction/istestclass, so makes sense to inherit +@@ -50,7 +98,9 @@ class SpecModule(RelaxedMixin, Module): + + @classmethod + def from_parent(cls, parent, fspath): +- if pytest_version_info >= (5, 4): ++ if pytest_version_info >= (7, 0): ++ return super(SpecModule, cls).from_parent(parent, path=Path(fspath)) ++ elif pytest_version_info >= (5, 4): + return super(SpecModule, cls).from_parent(parent, fspath=fspath) + else: + return cls(parent=parent, fspath=fspath) +@@ -96,9 +146,7 @@ class SpecModule(RelaxedMixin, Module): + return collected + + +-# NOTE: no need to inherit from RelaxedMixin here as it doesn't do much by +-# its lonesome +-class SpecClass(Class): ++class SpecClass(RelaxedMixin, Class): + + @classmethod + def from_parent(cls, parent, name): +@@ -110,16 +158,39 @@ class SpecClass(Class): + def collect(self): + items = super(SpecClass, self).collect() + collected = [] +- # Replace Instance objects with SpecInstance objects that know how to +- # recurse into inner classes. +- # TODO: is this ever not a one-item list? Meh. + for item in items: +- item = SpecInstance.from_parent(item.parent, name=item.name) +- collected.append(item) ++ if pytest_version_info < (7, 0): ++ # Replace Instance objects with SpecInstance objects that know how to ++ # recurse into inner classes. ++ item = SpecInstance.from_parent(item.parent, name=item.name) ++ collected.append(item) ++ else: ++ # Pytest >= 7 collects the Functions in Class directly without Instance ++ # Replace any Class objects with SpecClass, and recurse into it. ++ if isinstance(item, Class): ++ subclass = SpecClass.from_parent(item.parent, name=item.name) ++ collected += subclass.collect() ++ else: ++ collected.append(item) + return collected + ++ def _getobj(self): ++ # Regular object-making first ++ obj = super(SpecClass, self)._getobj() ++ # Then decorate it with our parent's extra attributes, allowing nested ++ # test classes to appear as an aggregate of parents' "scopes". ++ # NOTE: of course, skipping if we've gone out the top into a module etc ++ if ( ++ pytest_version_info < (7, 0) ++ or not hasattr(self, "parent") ++ or not isinstance(self.parent, SpecClass) ++ ): ++ return obj ++ else: ++ return _get_obj_rec(obj, self.parent.obj) + + class SpecInstance(RelaxedMixin, Instance): ++ # This is only instantiated in Pytest < 7 + + @classmethod + def from_parent(cls, parent, name): +@@ -141,61 +212,19 @@ class SpecInstance(RelaxedMixin, Instanc + or not isinstance(self.parent.parent, SpecInstance) + ): + return obj +- parent_obj = self.parent.parent.obj +- # Obtain parent attributes, etc not found on our obj (serves as both a +- # useful identifier of "stuff added to an outer class" and a way of +- # ensuring that we can override such attrs), and set them on obj +- delta = set(dir(parent_obj)).difference(set(dir(obj))) +- for name in delta: +- value = getattr(parent_obj, name) +- # Pytest's pytestmark attributes always get skipped, we don't want +- # to spread that around where it's not wanted. (Besides, it can +- # cause a lot of collection level warnings.) +- if name == "pytestmark": +- continue +- # Classes get skipped; they'd always just be other 'inner' classes +- # that we don't want to copy elsewhere. +- if isinstance(value, six.class_types): +- continue +- # Functions (methods) may get skipped, or not, depending: +- if isinstance(value, types.MethodType): +- # If they look like tests, they get skipped; don't want to copy +- # tests around! +- if istestfunction(name): +- continue +- # Non-test == they're probably lifecycle methods +- # (setup/teardown) or helpers (_do_thing). Rebind them to the +- # target instance, otherwise the 'self' in the setup/helper is +- # not the same 'self' as that in the actual test method it runs +- # around or within! +- # TODO: arguably, all setup or helper methods should become +- # autouse class fixtures (see e.g. pytest docs under 'xunit +- # setup on steroids') +- func = six.get_method_function(value) +- setattr(obj, name, six.create_bound_method(func, obj)) +- # Anything else should be some data-type attribute, which is copied +- # verbatim / by-value. +- else: +- setattr(obj, name, value) +- return obj ++ else: ++ return _get_obj_rec(obj, self.parent.parent.obj) + +- # Stub for pytest >=3.0,<3.3 where _makeitem did not exist +- def makeitem(self, *args, **kwargs): +- return self._makeitem(*args, **kwargs) + +- def _makeitem(self, name, obj): +- # More pytestmark skipping. +- if name == "pytestmark": +- return +- # NOTE: no need to modify collect() this time, just mutate item +- # creation. TODO: but if collect() is still public, let's move to that +- # sometime, if that'll work as well. +- superb = super(SpecInstance, self) +- attr = "_makeitem" if hasattr(superb, "_makeitem") else "makeitem" +- item = getattr(superb, attr)(name, obj) +- # Replace any Class objects with SpecClass; this will automatically +- # recurse. +- # TODO: can we unify this with SpecModule's same bits? +- if isinstance(item, Class): +- item = SpecClass.from_parent(item.parent, name=item.name) +- return item ++ def collect(self): ++ items = super(SpecInstance, self).collect() ++ collected = [] ++ for item in items: ++ # Replace any Class objects with SpecClass, and recurse into it. ++ if isinstance(item, Class): ++ cls = SpecClass.from_parent(item.parent, name=item.name) ++ for item in cls.collect(): ++ collected.append(item) ++ else: ++ collected.append(item) ++ return collected diff --git a/pytest-relaxed-pr10.patch b/pytest-relaxed-pr10.patch new file mode 100644 index 0000000..d5b91c6 --- /dev/null +++ b/pytest-relaxed-pr10.patch @@ -0,0 +1,175 @@ +From 3423a446a49548b80e13fa78fe1c3cbd21968457 Mon Sep 17 00:00:00 2001 +From: Stanislav Levin +Date: Thu, 7 May 2020 18:46:52 +0300 +Subject: [PATCH 1/2] Fix deprecated direct constructors for Nodes + +As of 5.4.0 Pytest emits deprecation warnings [0]: +``` +PytestDeprecationWarning: direct construction of Spec* has been +deprecated, please use Spec*.from_parent. +``` + +[0]: https://docs.pytest.org/en/5.4.0/changelog.html#deprecations + +Signed-off-by: Stanislav Levin +--- + pytest_relaxed/classes.py | 31 ++++++++++++++++++++++++++++--- + pytest_relaxed/plugin.py | 2 +- + 2 files changed, 29 insertions(+), 4 deletions(-) + +diff --git a/pytest_relaxed/classes.py b/pytest_relaxed/classes.py +index 10615bc..26edf4e 100644 +--- a/pytest_relaxed/classes.py ++++ b/pytest_relaxed/classes.py +@@ -3,12 +3,15 @@ + + import six + ++from pytest import __version__ as pytest_version + from pytest import Class, Instance, Module + + # NOTE: don't see any other way to get access to pytest innards besides using + # the underscored name :( + from _pytest.python import PyCollector + ++pytest_version_info = tuple(map(int, pytest_version.split(".")[:3])) ++ + + # NOTE: these are defined here for reuse by both pytest's own machinery and our + # internal bits. +@@ -45,6 +48,13 @@ def istestfunction(self, obj, name): + + class SpecModule(RelaxedMixin, Module): + ++ @classmethod ++ def from_parent(cls, parent, fspath): ++ if pytest_version_info >= (5, 4): ++ return super(SpecModule, cls).from_parent(parent, fspath=fspath) ++ else: ++ return cls(parent=parent, fspath=fspath) ++ + def _is_test_obj(self, test_func, obj, name): + # First run our super() test, which should be RelaxedMixin's. + good_name = getattr(super(SpecModule, self), test_func)(obj, name) +@@ -69,6 +79,7 @@ def collect(self): + # Get whatever our parent picked up as valid test items (given our + # relaxed name constraints above). It'll be nearly all module contents. + items = super(SpecModule, self).collect() ++ + collected = [] + for item in items: + # Replace Class objects with recursive SpecInstances (via +@@ -80,7 +91,7 @@ def collect(self): + # them to be handled by pytest's own unittest support) but since + # those are almost always in test_prefixed_filenames anyways...meh + if isinstance(item, Class): +- item = SpecClass(item.name, item.parent) ++ item = SpecClass.from_parent(item.parent, name=item.name) + collected.append(item) + return collected + +@@ -89,6 +100,13 @@ def collect(self): + # its lonesome + class SpecClass(Class): + ++ @classmethod ++ def from_parent(cls, parent, name): ++ if pytest_version_info >= (5, 4): ++ return super(SpecClass, cls).from_parent(parent, name=name) ++ else: ++ return cls(parent=parent, name=name) ++ + def collect(self): + items = super(SpecClass, self).collect() + collected = [] +@@ -96,13 +114,20 @@ def collect(self): + # recurse into inner classes. + # TODO: is this ever not a one-item list? Meh. + for item in items: +- item = SpecInstance(name=item.name, parent=item.parent) ++ item = SpecInstance.from_parent(item.parent, name=item.name) + collected.append(item) + return collected + + + class SpecInstance(RelaxedMixin, Instance): + ++ @classmethod ++ def from_parent(cls, parent, name): ++ if pytest_version_info >= (5, 4): ++ return super(SpecInstance, cls).from_parent(parent, name=name) ++ else: ++ return cls(parent=parent, name=name) ++ + def _getobj(self): + # Regular object-making first + obj = super(SpecInstance, self)._getobj() +@@ -172,5 +197,5 @@ def _makeitem(self, name, obj): + # recurse. + # TODO: can we unify this with SpecModule's same bits? + if isinstance(item, Class): +- item = SpecClass(item.name, item.parent) ++ item = SpecClass.from_parent(item.parent, name=item.name) + return item +diff --git a/pytest_relaxed/plugin.py b/pytest_relaxed/plugin.py +index 0f5a389..8f64358 100644 +--- a/pytest_relaxed/plugin.py ++++ b/pytest_relaxed/plugin.py +@@ -28,7 +28,7 @@ def pytest_collect_file(path, parent): + ): + # Then use our custom module class which performs modified + # function/class selection as well as class recursion +- return SpecModule(path, parent) ++ return SpecModule.from_parent(parent, fspath=path) + + + @pytest.mark.trylast # So we can be sure builtin terminalreporter exists + +From 6360ba2cc46b597d20478aaee1d6bd1d73588a88 Mon Sep 17 00:00:00 2001 +From: Stanislav Levin +Date: Fri, 6 Dec 2019 16:13:06 +0300 +Subject: [PATCH 2/2] Fixed expected colored statistics + +As of 5.3.0 Pytest improved colored statistics of the outcome: +https://docs.pytest.org/en/5.3.0/changelog.html#improvements + +Signed-off-by: Stanislav Levin +--- + tests/test_display.py | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/tests/test_display.py b/tests/test_display.py +index 5b7f9c8..2884c84 100644 +--- a/tests/test_display.py ++++ b/tests/test_display.py +@@ -1,4 +1,5 @@ + from pytest import skip ++from pytest import __version__ as pytest_version + + # Load some fixtures we expose, without actually loading our entire plugin + from pytest_relaxed.fixtures import environ # noqa +@@ -8,6 +9,8 @@ + # (May not be feasible if it has to assume something about how our collection + # works?) CLI option (99% sure we can hook into that as a plugin)? + ++pytest_version_info = tuple(map(int, pytest_version.split(".")[:3])) ++ + + def _expect_regular_output(testdir): + output = testdir.runpytest().stdout.str() +@@ -225,7 +228,14 @@ def behavior_four(self): + assert "== FAILURES ==" in output + assert "AssertionError" in output + # Summary +- assert "== 1 failed, 4 passed, 1 skipped in " in output ++ if pytest_version_info >= (5, 3): ++ expected_out = ( ++ "== \x1b[31m\x1b[1m1 failed\x1b[0m, \x1b[32m4 passed\x1b[0m, " ++ "\x1b[33m1 skipped\x1b[0m\x1b[31m in " ++ ) ++ else: ++ expected_out = "== 1 failed, 4 passed, 1 skipped in " ++ assert expected_out in output + + def test_nests_many_levels_deep_no_problem(self, testdir): + testdir.makepyfile( diff --git a/python-pytest-relaxed.spec b/python-pytest-relaxed.spec index 1cba7e8..e37e8c6 100644 --- a/python-pytest-relaxed.spec +++ b/python-pytest-relaxed.spec @@ -6,13 +6,15 @@ the design (such as a decreased emphasis on the display side of things.) Name: python-%{srcname} Version: 1.1.5 -Release: 12 +Release: 13 Summary: Relaxed test discovery for pytest License: BSD URL: https://github.com/bitprophet/pytest-relaxed Source0: %{url}/archive/%{version}/%{srcname}-%{version}.tar.gz Patch0: 0001-upgrade-pytest-version.patch +Patch1: pytest-relaxed-pr10.patch +Patch2: pytest-6.1-and-7.patch BuildArch: noarch %description @@ -50,6 +52,9 @@ PYTHONPATH=%{buildroot}%{python3_sitelib} pytest-%{python3_version} %{python3_sitelib}/pytest_relaxed/ %changelog +* Fri May 13 2022 yaoxin - 1.1.5-13 +- Resolve the compilation failure in the check phase + * Fri Jan 29 2021 zhaorenhai - 1.1.5-12 - init spec of openEuler, referenced from Fedora.