Skip to content

Commit

Permalink
Make zope a semi-optional test dependency (#685)
Browse files Browse the repository at this point in the history
  • Loading branch information
pganssle committed Sep 3, 2020
1 parent 00c1c2c commit dfb2ee2
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 20 deletions.
1 change: 1 addition & 0 deletions 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.
2 changes: 1 addition & 1 deletion pyproject.toml
Expand Up @@ -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]
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Expand Up @@ -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"]
)
Expand Down
52 changes: 35 additions & 17 deletions tests/test_validators.py
Expand Up @@ -7,7 +7,6 @@
import re

import pytest
import zope.interface

import attr

Expand All @@ -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`.
Expand Down Expand Up @@ -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):
"""
Expand All @@ -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 (
"<provides validator for interface {interface!r}>".format(
interface=IFoo
interface=ifoo
)
) == repr(v)

Expand Down

0 comments on commit dfb2ee2

Please sign in to comment.