From dfb2ee284d6229d8bffe6cba6be66a747116cd27 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Thu, 3 Sep 2020 00:56:17 -0400 Subject: [PATCH] Make `zope` a semi-optional test dependency (#685) --- changelog.d/685.change.rst | 1 + pyproject.toml | 2 +- setup.py | 4 +-- tests/test_validators.py | 52 +++++++++++++++++++++++++------------- 4 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 changelog.d/685.change.rst diff --git a/changelog.d/685.change.rst b/changelog.d/685.change.rst new file mode 100644 index 000000000..190f998fc --- /dev/null +++ b/changelog.d/685.change.rst @@ -0,0 +1 @@ +``zope.interface`` is now a "soft dependency" when running the test suite; if ``zope.interface`` is not installed when running the test suite, the interface-related tests will be automatically skipped. diff --git a/pyproject.toml b/pyproject.toml index a3f207904..35d675236 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ multi_line_output=3 use_parentheses=true known_first_party="attr" -known_third_party=["attr", "hypothesis", "pytest", "setuptools", "six", "zope"] +known_third_party=["attr", "hypothesis", "pytest", "setuptools", "six"] [tool.towncrier] diff --git a/setup.py b/setup.py index ae012aa32..6ecc1633a 100644 --- a/setup.py +++ b/setup.py @@ -38,16 +38,16 @@ INSTALL_REQUIRES = [] EXTRAS_REQUIRE = { "docs": ["sphinx", "sphinx-rtd-theme", "zope.interface"], - "tests": [ + "tests_no_zope": [ # 5.0 introduced toml; parallel was broken until 5.0.2 "coverage[toml]>=5.0.2", "hypothesis", "pympler", "pytest>=4.3.0", # 4.3.0 dropped last use of `convert` "six", - "zope.interface", ], } +EXTRAS_REQUIRE["tests"] = EXTRAS_REQUIRE["tests_no_zope"] + ["zope.interface"] EXTRAS_REQUIRE["dev"] = ( EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["docs"] + ["pre-commit"] ) diff --git a/tests/test_validators.py b/tests/test_validators.py index e465001aa..4aeec9990 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -7,7 +7,6 @@ import re import pytest -import zope.interface import attr @@ -29,6 +28,19 @@ from .utils import simple_attr +@pytest.fixture(scope="module") +def zope_interface(): + """Provides ``zope.interface`` if available, skipping the test if not.""" + try: + import zope.interface + except ImportError: + raise pytest.skip( + "zope-related tests skipped when zope.interface is not installed" + ) + + return zope.interface + + class TestInstanceOf(object): """ Tests for `instance_of`. @@ -217,16 +229,22 @@ class C(object): assert C.__attrs_attrs__[0].validator == C.__attrs_attrs__[1].validator -class IFoo(zope.interface.Interface): - """ - An interface. - """ +@pytest.fixture(scope="module") +def ifoo(zope_interface): + """Provides a test ``zope.interface.Interface`` in ``zope`` tests.""" - def f(): + class IFoo(zope_interface.Interface): """ - A function called f. + An interface. """ + def f(): + """ + A function called f. + """ + + return IFoo + class TestProvides(object): """ @@ -239,46 +257,46 @@ def test_in_all(self): """ assert provides.__name__ in validator_module.__all__ - def test_success(self): + def test_success(self, zope_interface, ifoo): """ Nothing happens if value provides requested interface. """ - @zope.interface.implementer(IFoo) + @zope_interface.implementer(ifoo) class C(object): def f(self): pass - v = provides(IFoo) + v = provides(ifoo) v(None, simple_attr("x"), C()) - def test_fail(self): + def test_fail(self, ifoo): """ Raises `TypeError` if interfaces isn't provided by value. """ value = object() a = simple_attr("x") - v = provides(IFoo) + v = provides(ifoo) with pytest.raises(TypeError) as e: v(None, a, value) assert ( "'x' must provide {interface!r} which {value!r} doesn't.".format( - interface=IFoo, value=value + interface=ifoo, value=value ), a, - IFoo, + ifoo, value, ) == e.value.args - def test_repr(self): + def test_repr(self, ifoo): """ Returned validator has a useful `__repr__`. """ - v = provides(IFoo) + v = provides(ifoo) assert ( "".format( - interface=IFoo + interface=ifoo ) ) == repr(v)