Merge pull request #2641 from RonnyPfannschmidt/introduce-attrs
[RFC] Introduce attrs
This commit is contained in:
commit
c33074c8b9
|
@ -7,6 +7,7 @@ import warnings
|
|||
import py
|
||||
from py._code.code import FormattedExcinfo
|
||||
|
||||
import attr
|
||||
import _pytest
|
||||
from _pytest import nodes
|
||||
from _pytest._code.code import TerminalRepr
|
||||
|
@ -822,13 +823,21 @@ def pytest_fixture_setup(fixturedef, request):
|
|||
return result
|
||||
|
||||
|
||||
class FixtureFunctionMarker:
|
||||
def __init__(self, scope, params, autouse=False, ids=None, name=None):
|
||||
self.scope = scope
|
||||
self.params = params
|
||||
self.autouse = autouse
|
||||
self.ids = ids
|
||||
self.name = name
|
||||
def _ensure_immutable_ids(ids):
|
||||
if ids is None:
|
||||
return
|
||||
if callable(ids):
|
||||
return ids
|
||||
return tuple(ids)
|
||||
|
||||
|
||||
@attr.s(frozen=True)
|
||||
class FixtureFunctionMarker(object):
|
||||
scope = attr.ib()
|
||||
params = attr.ib(convert=attr.converters.optional(tuple))
|
||||
autouse = attr.ib(default=False)
|
||||
ids = attr.ib(default=None, convert=_ensure_immutable_ids)
|
||||
name = attr.ib(default=None)
|
||||
|
||||
def __call__(self, function):
|
||||
if isclass(function):
|
||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import absolute_import, division, print_function
|
|||
|
||||
import inspect
|
||||
import warnings
|
||||
import attr
|
||||
from collections import namedtuple
|
||||
from operator import attrgetter
|
||||
from six.moves import map
|
||||
|
@ -185,22 +186,26 @@ def pytest_collection_modifyitems(items, config):
|
|||
items[:] = remaining
|
||||
|
||||
|
||||
class MarkMapping:
|
||||
@attr.s
|
||||
class MarkMapping(object):
|
||||
"""Provides a local mapping for markers where item access
|
||||
resolves to True if the marker is present. """
|
||||
|
||||
def __init__(self, keywords):
|
||||
mymarks = set()
|
||||
own_mark_names = attr.ib()
|
||||
|
||||
@classmethod
|
||||
def from_keywords(cls, keywords):
|
||||
mark_names = set()
|
||||
for key, value in keywords.items():
|
||||
if isinstance(value, MarkInfo) or isinstance(value, MarkDecorator):
|
||||
mymarks.add(key)
|
||||
self._mymarks = mymarks
|
||||
mark_names.add(key)
|
||||
return cls(mark_names)
|
||||
|
||||
def __getitem__(self, name):
|
||||
return name in self._mymarks
|
||||
return name in self.own_mark_names
|
||||
|
||||
|
||||
class KeywordMapping:
|
||||
class KeywordMapping(object):
|
||||
"""Provides a local mapping for keywords.
|
||||
Given a list of names, map any substring of one of these names to True.
|
||||
"""
|
||||
|
@ -217,7 +222,7 @@ class KeywordMapping:
|
|||
|
||||
def matchmark(colitem, markexpr):
|
||||
"""Tries to match on any marker names, attached to the given colitem."""
|
||||
return eval(markexpr, {}, MarkMapping(colitem.keywords))
|
||||
return eval(markexpr, {}, MarkMapping.from_keywords(colitem.keywords))
|
||||
|
||||
|
||||
def matchkeyword(colitem, keywordexpr):
|
||||
|
@ -306,7 +311,21 @@ def istestfunc(func):
|
|||
getattr(func, "__name__", "<lambda>") != "<lambda>"
|
||||
|
||||
|
||||
class MarkDecorator:
|
||||
@attr.s(frozen=True)
|
||||
class Mark(object):
|
||||
name = attr.ib()
|
||||
args = attr.ib()
|
||||
kwargs = attr.ib()
|
||||
|
||||
def combined_with(self, other):
|
||||
assert self.name == other.name
|
||||
return Mark(
|
||||
self.name, self.args + other.args,
|
||||
dict(self.kwargs, **other.kwargs))
|
||||
|
||||
|
||||
@attr.s
|
||||
class MarkDecorator(object):
|
||||
""" A decorator for test functions and test classes. When applied
|
||||
it will create :class:`MarkInfo` objects which may be
|
||||
:ref:`retrieved by hooks as item keywords <excontrolskip>`.
|
||||
|
@ -340,9 +359,7 @@ class MarkDecorator:
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, mark):
|
||||
assert isinstance(mark, Mark), repr(mark)
|
||||
self.mark = mark
|
||||
mark = attr.ib(validator=attr.validators.instance_of(Mark))
|
||||
|
||||
name = alias('mark.name')
|
||||
args = alias('mark.args')
|
||||
|
@ -422,15 +439,6 @@ def store_legacy_markinfo(func, mark):
|
|||
holder.add_mark(mark)
|
||||
|
||||
|
||||
class Mark(namedtuple('Mark', 'name, args, kwargs')):
|
||||
|
||||
def combined_with(self, other):
|
||||
assert self.name == other.name
|
||||
return Mark(
|
||||
self.name, self.args + other.args,
|
||||
dict(self.kwargs, **other.kwargs))
|
||||
|
||||
|
||||
class MarkInfo(object):
|
||||
""" Marking object created by :class:`MarkDecorator` instances. """
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pytest now depends on `attrs <https://pypi.org/project/attrs/>`_ for internal structures to ease code maintainability.
|
7
setup.py
7
setup.py
|
@ -43,8 +43,13 @@ def has_environment_marker_support():
|
|||
|
||||
|
||||
def main():
|
||||
install_requires = ['py>=1.4.34', 'six>=1.10.0', 'setuptools']
|
||||
extras_require = {}
|
||||
install_requires = [
|
||||
'py>=1.4.33',
|
||||
'six>=1.10.0',
|
||||
'setuptools',
|
||||
'attrs>=17.2.0',
|
||||
]
|
||||
# if _PYTEST_SETUP_SKIP_PLUGGY_DEP is set, skip installing pluggy;
|
||||
# used by tox.ini to test with pluggy master
|
||||
if '_PYTEST_SETUP_SKIP_PLUGGY_DEP' not in os.environ:
|
||||
|
|
Loading…
Reference in New Issue