Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make zope a semi-optional test dependency #685

Merged
merged 4 commits into from Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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