Skip to content

Add package scoped fixtures #2283 #3386

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

Closed
wants to merge 59 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
ff3d13e
Update typo in fixture.rst
nicoddemus Mar 26, 2018
34afded
Update pytest.raises to raise a TypeError when an invalid keyword arg…
jeffreyrack Mar 28, 2018
a5d9fbe
Change pytest.raises to use match instead of matches
jeffreyrack Mar 28, 2018
bfe773b
Use shorter 'if kwargs' check as requested during review
nicoddemus Mar 28, 2018
7656581
Update changelog formatting
nicoddemus Mar 28, 2018
2efaf39
Merge pull request #3349 from jeffreyrack/3348-unknown-argument
RonnyPfannschmidt Mar 28, 2018
0a3cd88
Add docs about using pytest.param in parametrized fixtures
nicoddemus Mar 28, 2018
f1c9efc
Merge pull request #3353 from nicoddemus/fixture-param-marks-docs
RonnyPfannschmidt Mar 29, 2018
faded25
chage collections.abc import to fix deprecation warnings on python 3.7
irmen Mar 29, 2018
8ca9321
Move compatibility imports to compat.py and fix linting
nicoddemus Mar 29, 2018
6a81aae
Move compatibility imports to compat.py and fix linting
nicoddemus Mar 29, 2018
e5eba84
Remove stale CHANGELOG entries
nicoddemus Mar 29, 2018
daf1de0
Add reference docs for pytest_sessionstart/finish and update their do…
nicoddemus Mar 29, 2018
3fc2c94
Switch imports based on python versions, my bad
nicoddemus Mar 30, 2018
77128ee
Merge pull request #3356 from nicoddemus/remove-stale-changelog-entries
flub Mar 30, 2018
211f3c4
record_property is no longer experimental
RonnyPfannschmidt Apr 1, 2018
9a62ebf
Merge pull request #3355 from irmen/py37deprfixes
nicoddemus Apr 2, 2018
9326759
Merge pull request #3357 from nicoddemus/session-hooks-ref
RonnyPfannschmidt Apr 3, 2018
7c0c91a
fix record_property test
RonnyPfannschmidt Apr 3, 2018
9aa2a83
Use correct spelling for "more-itertools"
Apr 3, 2018
ad0b433
Merge pull request #3364 from sscherfke/more-itertools
RonnyPfannschmidt Apr 3, 2018
2018cf1
fix the record_property test
RonnyPfannschmidt Apr 5, 2018
db24723
no-capture in sample code demo'ing plugin
dchudz Apr 5, 2018
ef34de9
Merge pull request #3360 from RonnyPfannschmidt/xml_property_yay
nicoddemus Apr 5, 2018
ab91771
Merge pull request #3370 from dchudz/patch-1
nicoddemus Apr 5, 2018
f17dfa4
Remove label descriptions from development guide
nicoddemus Apr 5, 2018
5d4fe87
Merge pull request #3371 from nicoddemus/remove-labels-descriptions
RonnyPfannschmidt Apr 6, 2018
ec2d822
Fix issue #3372
Ohj8odah Apr 6, 2018
0cd74dc
Ensure object is class before calling issubclass.
Ohj8odah Apr 6, 2018
846d91f
Follow Ronny's advice and use ``type`` in ``base_type``.
Ohj8odah Apr 6, 2018
5bd8561
linting: unfortunate dedent be gone.
Ohj8odah Apr 6, 2018
e012dbe
Merge pull request #3373 from backbord/master
nicoddemus Apr 7, 2018
d26379e
Add package scoped fixtures #2283
Apr 11, 2018
09978c3
Updated AUTHORS and added item to changelog.
Apr 11, 2018
52a3bd2
Update typo in fixture.rst
nicoddemus Mar 26, 2018
94eb0de
Update pytest.raises to raise a TypeError when an invalid keyword arg…
jeffreyrack Mar 28, 2018
df4657a
Change pytest.raises to use match instead of matches
jeffreyrack Mar 28, 2018
6ab0431
Use shorter 'if kwargs' check as requested during review
nicoddemus Mar 28, 2018
942db75
Update changelog formatting
nicoddemus Mar 28, 2018
0d36860
Add docs about using pytest.param in parametrized fixtures
nicoddemus Mar 28, 2018
60444d2
Remove stale CHANGELOG entries
nicoddemus Mar 29, 2018
2d2e187
chage collections.abc import to fix deprecation warnings on python 3.7
irmen Mar 29, 2018
c52a092
Move compatibility imports to compat.py and fix linting
nicoddemus Mar 29, 2018
1631c7f
Move compatibility imports to compat.py and fix linting
nicoddemus Mar 29, 2018
67443b5
Switch imports based on python versions, my bad
nicoddemus Mar 30, 2018
8163f1a
Add reference docs for pytest_sessionstart/finish and update their do…
nicoddemus Mar 29, 2018
478a6f0
Use correct spelling for "more-itertools"
Apr 3, 2018
9cf7819
record_property is no longer experimental
RonnyPfannschmidt Apr 1, 2018
b40eded
fix record_property test
RonnyPfannschmidt Apr 3, 2018
e6d17aa
fix the record_property test
RonnyPfannschmidt Apr 5, 2018
6b2bda1
no-capture in sample code demo'ing plugin
dchudz Apr 5, 2018
dbea2b3
Remove label descriptions from development guide
nicoddemus Apr 5, 2018
cd0c6e0
Fix issue #3372
Ohj8odah Apr 6, 2018
3234cbe
Ensure object is class before calling issubclass.
Ohj8odah Apr 6, 2018
d28030f
Follow Ronny's advice and use ``type`` in ``base_type``.
Ohj8odah Apr 6, 2018
5f27fa4
linting: unfortunate dedent be gone.
Ohj8odah Apr 6, 2018
adfaca6
Add package scoped fixtures #2283
Apr 11, 2018
633578a
Updated AUTHORS and added item to changelog.
Apr 11, 2018
0017e6a
Merge branch 'master' of github.com:jonozzz/pytest
Apr 11, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Hugo van Kemenade
Hui Wang (coldnight)
Ian Bicking
Ian Lesperance
Ionuț Turturică
Jaap Broekhuizen
Jan Balster
Janne Vanhala
Expand Down Expand Up @@ -190,6 +191,7 @@ Tareq Alayan
Ted Xiao
Thomas Grainger
Thomas Hisch
Tim Strazny
Tom Dalton
Tom Viner
Trevor Bekolay
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ Trivial/Internal Changes
- Internal ``mark.py`` module has been turned into a package. (`#3250
<https://github.com/pytest-dev/pytest/issues/3250>`_)

- ``pytest`` now depends on the `more_itertools
- ``pytest`` now depends on the `more-itertools
<https://github.com/erikrose/more-itertools>`_ package. (`#3265
<https://github.com/pytest-dev/pytest/issues/3265>`_)

Expand Down
2 changes: 1 addition & 1 deletion _pytest/assertion/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import _pytest._code
import py
import six
from collections import Sequence
from ..compat import Sequence

u = six.text_type

Expand Down
8 changes: 8 additions & 0 deletions _pytest/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@
PY36 = sys.version_info[:2] >= (3, 6)
MODULE_NOT_FOUND_ERROR = 'ModuleNotFoundError' if PY36 else 'ImportError'

if _PY3:
from collections.abc import MutableMapping as MappingMixin # noqa
from collections.abc import Sequence # noqa
else:
# those raise DeprecationWarnings in Python >=3.7
from collections import MutableMapping as MappingMixin # noqa
from collections import Sequence # noqa


def _format_args(func):
return str(signature(func))
Expand Down
10 changes: 7 additions & 3 deletions _pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def pytest_sessionstart(session):
import _pytest.nodes

scopename2class.update({
'package': _pytest.python.Package,
'class': _pytest.python.Class,
'module': _pytest.python.Module,
'function': _pytest.nodes.Item,
Expand All @@ -48,6 +49,7 @@ def pytest_sessionstart(session):


scope2props = dict(session=())
scope2props["package"] = ("fspath",)
scope2props["module"] = ("fspath", "module")
scope2props["class"] = scope2props["module"] + ("cls",)
scope2props["instance"] = scope2props["class"] + ("instance", )
Expand Down Expand Up @@ -156,9 +158,11 @@ def get_parametrized_fixture_keys(item, scopenum):
continue
if scopenum == 0: # session
key = (argname, param_index)
elif scopenum == 1: # module
elif scopenum == 1: # package
key = (argname, param_index, item.fspath)
elif scopenum == 2: # class
elif scopenum == 2: # module
key = (argname, param_index, item.fspath)
elif scopenum == 3: # class
key = (argname, param_index, item.fspath, item.cls)
yield key

Expand Down Expand Up @@ -596,7 +600,7 @@ class ScopeMismatchError(Exception):
"""


scopes = "session module class function".split()
scopes = "session package module class function".split()
scopenum_function = scopes.index("function")


Expand Down
5 changes: 3 additions & 2 deletions _pytest/hookspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,14 +413,15 @@ def pytest_fixture_post_finalizer(fixturedef, request):


def pytest_sessionstart(session):
""" before session.main() is called.
""" called after the ``Session`` object has been created and before performing collection
and entering the run test loop.

:param _pytest.main.Session session: the pytest session object
"""


def pytest_sessionfinish(session, exitstatus):
""" whole test run finishes.
""" called after whole test run finished, right before returning the exit status to the system.

:param _pytest.main.Session session: the pytest session object
:param int exitstatus: the status which pytest will return to the system
Expand Down
5 changes: 0 additions & 5 deletions _pytest/junitxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,6 @@ def record_property(request):
def test_function(record_property):
record_property("example_key", 1)
"""
request.node.warn(
code='C3',
message='record_property is an experimental feature',
)

def append_property(name, value):
request.node.user_properties.append((name, value))
return append_property
Expand Down
31 changes: 22 additions & 9 deletions _pytest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,17 +405,30 @@ def collect(self):

def _collect(self, arg):
names = self._parsearg(arg)
path = names.pop(0)
if path.check(dir=1):
argpath = names.pop(0)
paths = []
if argpath.check(dir=1):
assert not names, "invalid arg %r" % (arg,)
for path in path.visit(fil=lambda x: x.check(file=1),
rec=self._recurse, bf=True, sort=True):
for x in self._collectfile(path):
yield x
for path in argpath.visit(fil=lambda x: x.check(file=1),
rec=self._recurse, bf=True, sort=True):
pkginit = path.dirpath().join('__init__.py')
if pkginit.exists() and not any(x in pkginit.parts() for x in paths):
for x in self._collectfile(pkginit):
yield x
paths.append(x.fspath.dirpath())

if not any(x in path.parts() for x in paths):
for x in self._collectfile(path):
yield x
else:
assert path.check(file=1)
for x in self.matchnodes(self._collectfile(path), names):
yield x
assert argpath.check(file=1)
pkginit = argpath.dirpath().join('__init__.py')
if not self.isinitpath(argpath) and pkginit.exists():
for x in self._collectfile(pkginit):
yield x
else:
for x in self.matchnodes(self._collectfile(argpath), names):
yield x

def _collectfile(self, path):
ihook = self.gethookproxy(path)
Expand Down
3 changes: 2 additions & 1 deletion _pytest/mark/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class MarkerError(Exception):


def param(*values, **kw):
"""Specify a parameter in a `pytest.mark.parametrize`_ call.
"""Specify a parameter in `pytest.mark.parametrize`_ calls or
:ref:`parametrized fixtures <fixture-parametrize-marks>`.

.. code-block:: python

Expand Down
7 changes: 6 additions & 1 deletion _pytest/mark/structures.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from collections import namedtuple, MutableMapping as MappingMixin
import sys
if sys.version_info >= (3, 4):
from collections.abc import MutableMapping as MappingMixin
else:
from collections import MutableMapping as MappingMixin
from collections import namedtuple
import warnings
from operator import attrgetter
import inspect
Expand Down
50 changes: 49 additions & 1 deletion _pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from _pytest.config import hookimpl

import _pytest
from _pytest.main import Session
import pluggy
from _pytest import fixtures
from _pytest import nodes
Expand Down Expand Up @@ -157,7 +158,7 @@ def pytest_collect_file(path, parent):
ext = path.ext
if ext == ".py":
if not parent.session.isinitpath(path):
for pat in parent.config.getini('python_files'):
for pat in parent.config.getini('python_files') + ['__init__.py']:
if path.fnmatch(pat):
break
else:
Expand All @@ -167,9 +168,24 @@ def pytest_collect_file(path, parent):


def pytest_pycollect_makemodule(path, parent):
if path.basename == '__init__.py':
return Package(path, parent)
return Module(path, parent)


def pytest_ignore_collect(path, config):
# Skip duplicate packages.
keepduplicates = config.getoption("keepduplicates")
if keepduplicates:
duplicate_paths = config.pluginmanager._duplicatepaths
if path.basename == '__init__.py':
if path in duplicate_paths:
return True
else:
duplicate_paths.add(path)



@hookimpl(hookwrapper=True)
def pytest_pycollect_makeitem(collector, name, obj):
outcome = yield
Expand Down Expand Up @@ -475,6 +491,38 @@ def setup(self):
self.addfinalizer(teardown_module)


class Package(Session, Module):

def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None):
session = parent.session
nodes.FSCollector.__init__(
self, fspath, parent=parent,
config=config, session=session, nodeid=nodeid)
self.name = fspath.pyimport().__name__
self.trace = session.trace
self._norecursepatterns = session._norecursepatterns
#keepduplicates = session.config.getoption("keepduplicates")
#if not keepduplicates:
for path in list(session.config.pluginmanager._duplicatepaths):
if path.dirname == fspath.dirname and path != fspath:
session.config.pluginmanager._duplicatepaths.remove(path)
pass

def isinitpath(self, path):
return path in self.session._initialpaths

def collect(self):
path = self.fspath.dirpath()
pkg_prefix = None
for path in path.visit(fil=lambda x: 1,
rec=self._recurse, bf=True, sort=True):
if pkg_prefix and pkg_prefix in path.parts():
continue
for x in self._collectfile(path):
yield x
if isinstance(x, Package):
pkg_prefix = path.dirpath()

def _get_xunit_setup_teardown(holder, attr_name, param_obj=None):
"""
Return a callable to perform xunit-style setup or teardown if
Expand Down
8 changes: 7 additions & 1 deletion _pytest/python_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys

import py
from six import binary_type, text_type
from six.moves import zip, filterfalse
from more_itertools.more import always_iterable

Expand Down Expand Up @@ -584,7 +585,8 @@ def raises(expected_exception, *args, **kwargs):

"""
__tracebackhide__ = True
for exc in filterfalse(isclass, always_iterable(expected_exception)):
base_type = (type, text_type, binary_type)
for exc in filterfalse(isclass, always_iterable(expected_exception, base_type)):
msg = ("exceptions must be old-style classes or"
" derived from BaseException, not %s")
raise TypeError(msg % type(exc))
Expand All @@ -597,6 +599,10 @@ def raises(expected_exception, *args, **kwargs):
message = kwargs.pop("message")
if "match" in kwargs:
match_expr = kwargs.pop("match")
if kwargs:
msg = 'Unexpected keyword arguments passed to pytest.raises: '
msg += ', '.join(kwargs.keys())
raise TypeError(msg)
return RaisesContext(expected_exception, message, match_expr)
elif isinstance(args[0], str):
code, = args
Expand Down
1 change: 0 additions & 1 deletion changelog/1478.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/1642.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/1713.doc.rst

This file was deleted.

1 change: 1 addition & 0 deletions changelog/2283.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Pytest now supports package-level fixtures.
1 change: 0 additions & 1 deletion changelog/2370.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/2405.feature.rst

This file was deleted.

2 changes: 0 additions & 2 deletions changelog/2770.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/2770.removal.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3034.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3084.removal

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3139.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3149.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3156.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3189.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3190.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3198.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3204.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3213.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3228.trivial.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3236.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3245.trivial.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3246.trival.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3250.trivial.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3255.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3265.trivial.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3268.trivial

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3291.trivial.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3292.trivial.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3296.feature

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3296.trivial

This file was deleted.

2 changes: 0 additions & 2 deletions changelog/3297.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3304.trivial

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3308.trivial.rst

This file was deleted.

1 change: 0 additions & 1 deletion changelog/3312.feature

This file was deleted.

3 changes: 0 additions & 3 deletions changelog/3314.bugfix.rst

This file was deleted.

1 change: 1 addition & 0 deletions changelog/3339.trivial
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Import some modules from ``collections`` instead of ``collections.abc`` as the former modules trigger ``DeprecationWarning`` in Python 3.7.
1 change: 1 addition & 0 deletions changelog/3348.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``pytest.raises`` now raises ``TypeError`` when receiving an unknown keyword argument.
2 changes: 2 additions & 0 deletions changelog/3360.trivial
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
record_property is no longer experimental, removing the warnings was forgotten.

1 change: 1 addition & 0 deletions changelog/3372.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``pytest.raises`` now works with exception classes that look like iterables.
Loading