[Python-modules-commits] [pytest] 01/07: Import pytest_3.1.3.orig.tar.gz
Sebastian Ramacher
sramacher at moszumanska.debian.org
Thu Jul 13 11:24:48 UTC 2017
This is an automated email from the git hooks/post-receive script.
sramacher pushed a commit to branch master
in repository pytest.
commit 1f3ae240b868a1fffc4506451270d91075308281
Author: Sebastian Ramacher <sramacher at debian.org>
Date: Thu Jul 13 13:23:20 2017 +0200
Import pytest_3.1.3.orig.tar.gz
---
.github/ISSUE_TEMPLATE.md | 8 ++
.github/PULL_REQUEST_TEMPLATE.md | 15 +++
.travis.yml | 51 ++++++++
CHANGELOG.rst | 52 +++++++-
LICENSE | 2 +-
MANIFEST.in | 39 ------
PKG-INFO | 4 +-
README.rst | 2 +-
_pytest/_code/code.py | 7 +-
_pytest/_version.py | 2 +-
_pytest/assertion/rewrite.py | 4 -
_pytest/doctest.py | 9 +-
_pytest/fixtures.py | 13 +-
_pytest/hookspec.py | 59 ++++++---
_pytest/impl | 254 ++++++++++++++++++++++++++++++++++++++
_pytest/main.py | 11 +-
_pytest/recwarn.py | 65 +++++-----
_pytest/terminal.py | 2 +-
appveyor.yml | 42 +++++++
changelog/_template.rst | 4 +-
doc/en/announce/index.rst | 1 +
doc/en/announce/release-3.1.3.rst | 23 ++++
doc/en/assert.rst | 4 +-
doc/en/doctest.rst | 2 +-
doc/en/example/markers.rst | 10 +-
doc/en/example/parametrize.rst | 2 +-
doc/en/fixture.rst | 100 +++++++++------
doc/en/getting-started.rst | 2 +-
doc/en/index.rst | 6 +-
doc/en/license.rst | 2 +-
doc/en/tmpdir.rst | 2 +-
doc/en/warnings.rst | 2 +-
doc/en/writing_plugins.rst | 6 +-
pyproject.toml | 4 +-
pytest.egg-info/PKG-INFO | 4 +-
pytest.egg-info/SOURCES.txt | 9 +-
scripts/check-manifest.py | 20 ---
tasks/__init__.py | 8 +-
tasks/requirements.txt | 3 +-
tasks/vendoring.py | 23 ++++
testing/acceptance_test.py | 4 +-
testing/code/test_excinfo.py | 23 ++++
testing/python/fixture.py | 33 +++++
testing/test_collection.py | 19 ++-
testing/test_doctest.py | 19 +++
testing/test_recwarn.py | 58 +++++++--
testing/test_runner.py | 4 +-
testing/test_terminal.py | 9 ++
tox.ini | 2 -
49 files changed, 829 insertions(+), 220 deletions(-)
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..fbcbb16
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,8 @@
+Thanks for submitting an issue!
+
+Here's a quick checklist in what to include:
+
+- [ ] Include a detailed description of the bug or suggestion
+- [ ] `pip list` of the virtual environment you are using
+- [ ] pytest and operating system versions
+- [ ] Minimal example if possible
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..ad3fea6
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,15 @@
+Thanks for submitting a PR, your contribution is really appreciated!
+
+Here's a quick checklist that should be present in PRs:
+
+- [ ] Add a new news fragment into the changelog folder
+ * name it `$issue_id.$type` for example (588.bug)
+ * if you don't have an issue_id change it to the pr id after creating the pr
+ * ensure type is one of `removal`, `feature`, `bugfix`, `vendor`, `doc` or `trivial`
+ * Make sure to use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files."
+- [ ] Target: for `bugfix`, `vendor`, `doc` or `trivial` fixes, target `master`; for removals or features target `features`;
+- [ ] Make sure to include reasonable tests for your change if necessary
+
+Unless your change is a trivial or a documentation fix (e.g., a typo or reword of a small section) please:
+
+- [ ] Add yourself to `AUTHORS`;
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..0a71e7d
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,51 @@
+sudo: false
+language: python
+python:
+ - '3.5'
+# command to install dependencies
+install: "pip install -U tox"
+# # command to run tests
+env:
+ matrix:
+ # coveralls is not listed in tox's envlist, but should run in travis
+ - TOXENV=coveralls
+ # note: please use "tox --listenvs" to populate the build matrix below
+ - TOXENV=linting
+ - TOXENV=py26
+ - TOXENV=py27
+ - TOXENV=py33
+ - TOXENV=py34
+ - TOXENV=py35
+ - TOXENV=pypy
+ - TOXENV=py27-pexpect
+ - TOXENV=py27-xdist
+ - TOXENV=py27-trial
+ - TOXENV=py35-pexpect
+ - TOXENV=py35-xdist
+ - TOXENV=py35-trial
+ - TOXENV=py27-nobyte
+ - TOXENV=doctesting
+ - TOXENV=freeze
+ - TOXENV=docs
+
+matrix:
+ include:
+ - env: TOXENV=py36
+ python: '3.6'
+ - env: TOXENV=py37
+ python: 'nightly'
+ allow_failures:
+ - env: TOXENV=py37
+ python: 'nightly'
+
+script: tox --recreate
+
+notifications:
+ irc:
+ channels:
+ - "chat.freenode.net#pytest"
+ on_success: change
+ on_failure: change
+ skip_join: true
+ email:
+ - pytest-commit at python.org
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 34fee33..1c1185d 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -8,6 +8,52 @@
.. towncrier release notes start
+Pytest 3.1.3 (2017-07-03)
+=========================
+
+Bug Fixes
+---------
+
+- Fix decode error in Python 2 for doctests in docstrings. (`#2434
+ <https://github.com/pytest-dev/pytest/issues/2434>`_)
+
+- Exceptions raised during teardown by finalizers are now suppressed until all
+ finalizers are called, with the initial exception reraised. (`#2440
+ <https://github.com/pytest-dev/pytest/issues/2440>`_)
+
+- Fix incorrect "collected items" report when specifying tests on the command-
+ line. (`#2464 <https://github.com/pytest-dev/pytest/issues/2464>`_)
+
+- ``deprecated_call`` in context-manager form now captures deprecation warnings
+ even if the same warning has already been raised. Also, ``deprecated_call``
+ will always produce the same error message (previously it would produce
+ different messages in context-manager vs. function-call mode). (`#2469
+ <https://github.com/pytest-dev/pytest/issues/2469>`_)
+
+- Fix issue where paths collected by pytest could have triple leading ``/``
+ characters. (`#2475 <https://github.com/pytest-dev/pytest/issues/2475>`_)
+
+- Fix internal error when trying to detect the start of a recursive traceback.
+ (`#2486 <https://github.com/pytest-dev/pytest/issues/2486>`_)
+
+
+Improved Documentation
+----------------------
+
+- Explicitly state for which hooks the calls stop after the first non-None
+ result. (`#2493 <https://github.com/pytest-dev/pytest/issues/2493>`_)
+
+
+Trivial/Internal Changes
+------------------------
+
+- Create invoke tasks for updating the vendored packages. (`#2474
+ <https://github.com/pytest-dev/pytest/issues/2474>`_)
+
+- Update copyright dates in LICENSE, README.rst and in the documentation.
+ (`#2499 <https://github.com/pytest-dev/pytest/issues/2499>`_)
+
+
Pytest 3.1.2 (2017-06-08)
=========================
@@ -25,9 +71,9 @@ Bug Fixes
- ``UnicodeWarning`` is issued from the internal pytest warnings plugin only
when the message contains non-ascii unicode (Python 2 only). (#2463)
-- Added a workaround for Python 3.6 WindowsConsoleIO breaking due to Pytests's
- FDCapture. Other code using console handles might still be affected by the
- very same issue and might require further workarounds/fixes, i.e. colorama.
+- Added a workaround for Python 3.6 ``WindowsConsoleIO`` breaking due to Pytests's
+ ``FDCapture``. Other code using console handles might still be affected by the
+ very same issue and might require further workarounds/fixes, i.e. ``colorama``.
(#2467)
diff --git a/LICENSE b/LICENSE
index 9e27bd7..629df45 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2004-2016 Holger Krekel and others
+Copyright (c) 2004-2017 Holger Krekel and others
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index abf57fe..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,39 +0,0 @@
-include CHANGELOG.rst
-include LICENSE
-include AUTHORS
-include pyproject.toml
-
-include README.rst
-include CONTRIBUTING.rst
-include HOWTORELEASE.rst
-
-include tox.ini
-include setup.py
-
-recursive-include changelog *
-recursive-include scripts *.py
-recursive-include scripts *.bat
-
-include .coveragerc
-
-recursive-include bench *.py
-recursive-include extra *.py
-
-graft testing
-graft doc
-prune doc/en/_build
-graft tasks
-
-exclude _pytest/impl
-
-graft _pytest/vendored_packages
-
-recursive-exclude * *.pyc *.pyo
-recursive-exclude testing/.hypothesis *
-recursive-exclude testing/freeze/~ *
-recursive-exclude testing/freeze/build *
-recursive-exclude testing/freeze/dist *
-
-exclude appveyor.yml
-exclude .travis.yml
-prune .github
diff --git a/PKG-INFO b/PKG-INFO
index e033632..2b08b6c 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: pytest
-Version: 3.1.2
+Version: 3.1.3
Summary: pytest: simple powerful testing with Python
Home-page: http://pytest.org
Author: Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others
@@ -110,7 +110,7 @@ Description: .. image:: http://docs.pytest.org/en/latest/_static/pytest1.png
License
-------
- Copyright Holger Krekel and others, 2004-2016.
+ Copyright Holger Krekel and others, 2004-2017.
Distributed under the terms of the `MIT`_ license, pytest is free and open source software.
diff --git a/README.rst b/README.rst
index 3a0abc5..cf2304e 100644
--- a/README.rst
+++ b/README.rst
@@ -102,7 +102,7 @@ Consult the `Changelog <http://docs.pytest.org/en/latest/changelog.html>`__ page
License
-------
-Copyright Holger Krekel and others, 2004-2016.
+Copyright Holger Krekel and others, 2004-2017.
Distributed under the terms of the `MIT`_ license, pytest is free and open source software.
diff --git a/_pytest/_code/code.py b/_pytest/_code/code.py
index 9b3408d..5b7cc41 100644
--- a/_pytest/_code/code.py
+++ b/_pytest/_code/code.py
@@ -640,8 +640,11 @@ class FormattedExcinfo(object):
).format(exc_type=type(e).__name__, exc_msg=safe_str(e), max_frames=max_frames, total=len(traceback))
traceback = traceback[:max_frames] + traceback[-max_frames:]
else:
- extraline = "!!! Recursion detected (same locals & position)"
- traceback = traceback[:recursionindex + 1]
+ if recursionindex is not None:
+ extraline = "!!! Recursion detected (same locals & position)"
+ traceback = traceback[:recursionindex + 1]
+ else:
+ extraline = None
return traceback, extraline
diff --git a/_pytest/_version.py b/_pytest/_version.py
index 0a1abdd..e03109e 100644
--- a/_pytest/_version.py
+++ b/_pytest/_version.py
@@ -1,4 +1,4 @@
# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
-version = '3.1.2'
+version = '3.1.3'
diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py
index 79943cc..6ec54d7 100644
--- a/_pytest/assertion/rewrite.py
+++ b/_pytest/assertion/rewrite.py
@@ -162,10 +162,6 @@ class AssertionRewritingHook(object):
# modules not passed explicitly on the command line are only
# rewritten if they match the naming convention for test files
for pat in self.fnpats:
- # use fnmatch instead of fn_pypath.fnmatch because the
- # latter might trigger an import to fnmatch.fnmatch
- # internally, which would cause this method to be
- # called recursively
if fn_pypath.fnmatch(pat):
state.trace("matched test file %r" % (fn,))
return True
diff --git a/_pytest/doctest.py b/_pytest/doctest.py
index 46b49d2..fde6dd7 100644
--- a/_pytest/doctest.py
+++ b/_pytest/doctest.py
@@ -177,7 +177,6 @@ class DoctestTextfile(pytest.Module):
name = self.fspath.basename
globs = {'__name__': '__main__'}
-
optionflags = get_optionflags(self)
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
checker=_get_checker())
@@ -218,9 +217,6 @@ class DoctestModule(pytest.Module):
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
checker=_get_checker())
- encoding = self.config.getini("doctest_encoding")
- _fix_spoof_python2(runner, encoding)
-
for test in finder.find(module, module.__name__):
if test.examples: # skip empty doctests
yield DoctestItem(test.name, self, runner, test)
@@ -332,7 +328,10 @@ def _get_report_choice(key):
def _fix_spoof_python2(runner, encoding):
"""
- Installs a "SpoofOut" into the given DebugRunner so it properly deals with unicode output.
+ Installs a "SpoofOut" into the given DebugRunner so it properly deals with unicode output. This
+ should patch only doctests for text files because they don't have a way to declare their
+ encoding. Doctests in docstrings from Python modules don't have the same problem given that
+ Python already decoded the strings.
This fixes the problem related in issue #2434.
"""
diff --git a/_pytest/fixtures.py b/_pytest/fixtures.py
index 1a6e245..64d21b9 100644
--- a/_pytest/fixtures.py
+++ b/_pytest/fixtures.py
@@ -733,10 +733,19 @@ class FixtureDef:
self._finalizer.append(finalizer)
def finish(self):
+ exceptions = []
try:
while self._finalizer:
- func = self._finalizer.pop()
- func()
+ try:
+ func = self._finalizer.pop()
+ func()
+ except:
+ exceptions.append(sys.exc_info())
+ if exceptions:
+ e = exceptions[0]
+ del exceptions # ensure we don't keep all frames alive because of the traceback
+ py.builtin._reraise(*e)
+
finally:
ihook = self._fixturemanager.session.ihook
ihook.pytest_fixture_post_finalizer(fixturedef=self)
diff --git a/_pytest/hookspec.py b/_pytest/hookspec.py
index e96fe32..2c9a661 100644
--- a/_pytest/hookspec.py
+++ b/_pytest/hookspec.py
@@ -73,7 +73,9 @@ def pytest_configure(config):
@hookspec(firstresult=True)
def pytest_cmdline_parse(pluginmanager, args):
- """return initialized config object, parsing the specified args. """
+ """return initialized config object, parsing the specified args.
+
+ Stops at first non-None result, see :ref:`firstresult` """
def pytest_cmdline_preparse(config, args):
"""(deprecated) modify command line arguments before option parsing. """
@@ -81,7 +83,9 @@ def pytest_cmdline_preparse(config, args):
@hookspec(firstresult=True)
def pytest_cmdline_main(config):
""" called for performing the main command line action. The default
- implementation will invoke the configure hooks and runtest_mainloop. """
+ implementation will invoke the configure hooks and runtest_mainloop.
+
+ Stops at first non-None result, see :ref:`firstresult` """
def pytest_load_initial_conftests(early_config, parser, args):
""" implements the loading of initial conftest files ahead
@@ -94,7 +98,9 @@ def pytest_load_initial_conftests(early_config, parser, args):
@hookspec(firstresult=True)
def pytest_collection(session):
- """ perform the collection protocol for the given session. """
+ """ perform the collection protocol for the given session.
+
+ Stops at first non-None result, see :ref:`firstresult` """
def pytest_collection_modifyitems(session, config, items):
""" called after collection has been performed, may filter or re-order
@@ -108,11 +114,15 @@ def pytest_ignore_collect(path, config):
""" return True to prevent considering this path for collection.
This hook is consulted for all files and directories prior to calling
more specific hooks.
+
+ Stops at first non-None result, see :ref:`firstresult`
"""
@hookspec(firstresult=True)
def pytest_collect_directory(path, parent):
- """ called before traversing a directory for collection files. """
+ """ called before traversing a directory for collection files.
+
+ Stops at first non-None result, see :ref:`firstresult` """
def pytest_collect_file(path, parent):
""" return collection Node or None for the given path. Any new node
@@ -133,7 +143,9 @@ def pytest_deselected(items):
@hookspec(firstresult=True)
def pytest_make_collect_report(collector):
- """ perform ``collector.collect()`` and return a CollectReport. """
+ """ perform ``collector.collect()`` and return a CollectReport.
+
+ Stops at first non-None result, see :ref:`firstresult` """
# -------------------------------------------------------------------------
# Python test function related hooks
@@ -145,15 +157,20 @@ def pytest_pycollect_makemodule(path, parent):
This hook will be called for each matching test module path.
The pytest_collect_file hook needs to be used if you want to
create test modules for files that do not match as a test module.
- """
+
+ Stops at first non-None result, see :ref:`firstresult` """
@hookspec(firstresult=True)
def pytest_pycollect_makeitem(collector, name, obj):
- """ return custom item/collector for a python object in a module, or None. """
+ """ return custom item/collector for a python object in a module, or None.
+
+ Stops at first non-None result, see :ref:`firstresult` """
@hookspec(firstresult=True)
def pytest_pyfunc_call(pyfuncitem):
- """ call underlying test function. """
+ """ call underlying test function.
+
+ Stops at first non-None result, see :ref:`firstresult` """
def pytest_generate_tests(metafunc):
""" generate (multiple) parametrized calls to a test function."""
@@ -163,7 +180,8 @@ def pytest_make_parametrize_id(config, val, argname):
"""Return a user-friendly string representation of the given ``val`` that will be used
by @pytest.mark.parametrize calls. Return None if the hook doesn't know about ``val``.
The parameter name is available as ``argname``, if required.
- """
+
+ Stops at first non-None result, see :ref:`firstresult` """
# -------------------------------------------------------------------------
# generic runtest related hooks
@@ -172,7 +190,9 @@ def pytest_make_parametrize_id(config, val, argname):
@hookspec(firstresult=True)
def pytest_runtestloop(session):
""" called for performing the main runtest loop
- (after collection finished). """
+ (after collection finished).
+
+ Stops at first non-None result, see :ref:`firstresult` """
def pytest_itemstart(item, node):
""" (deprecated, use pytest_runtest_logstart). """
@@ -190,7 +210,9 @@ def pytest_runtest_protocol(item, nextitem):
:py:func:`pytest_runtest_teardown`.
:return boolean: True if no further hook implementations should be invoked.
- """
+
+
+ Stops at first non-None result, see :ref:`firstresult` """
def pytest_runtest_logstart(nodeid, location):
""" signal the start of running a single test item. """
@@ -215,7 +237,8 @@ def pytest_runtest_makereport(item, call):
""" return a :py:class:`_pytest.runner.TestReport` object
for the given :py:class:`pytest.Item <_pytest.main.Item>` and
:py:class:`_pytest.runner.CallInfo`.
- """
+
+ Stops at first non-None result, see :ref:`firstresult` """
def pytest_runtest_logreport(report):
""" process a test setup/call/teardown report relating to
@@ -227,7 +250,9 @@ def pytest_runtest_logreport(report):
@hookspec(firstresult=True)
def pytest_fixture_setup(fixturedef, request):
- """ performs fixture setup execution. """
+ """ performs fixture setup execution.
+
+ Stops at first non-None result, see :ref:`firstresult` """
def pytest_fixture_post_finalizer(fixturedef):
""" called after fixture teardown, but before the cache is cleared so
@@ -277,7 +302,9 @@ def pytest_report_header(config, startdir):
@hookspec(firstresult=True)
def pytest_report_teststatus(report):
- """ return result-category, shortletter and verbose word for reporting."""
+ """ return result-category, shortletter and verbose word for reporting.
+
+ Stops at first non-None result, see :ref:`firstresult` """
def pytest_terminal_summary(terminalreporter, exitstatus):
""" add additional section in terminal summary reporting. """
@@ -295,7 +322,9 @@ def pytest_logwarning(message, code, nodeid, fslocation):
@hookspec(firstresult=True)
def pytest_doctest_prepare_content(content):
- """ return processed content for a given doctest"""
+ """ return processed content for a given doctest
+
+ Stops at first non-None result, see :ref:`firstresult` """
# -------------------------------------------------------------------------
# error handling and internal debugging hooks
diff --git a/_pytest/impl b/_pytest/impl
new file mode 100644
index 0000000..889e37e
--- /dev/null
+++ b/_pytest/impl
@@ -0,0 +1,254 @@
+Sorting per-resource
+-----------------------------
+
+for any given set of items:
+
+- collect items per session-scoped parametrized funcarg
+- re-order until items no parametrizations are mixed
+
+ examples:
+
+ test()
+ test1(s1)
+ test1(s2)
+ test2()
+ test3(s1)
+ test3(s2)
+
+ gets sorted to:
+
+ test()
+ test2()
+ test1(s1)
+ test3(s1)
+ test1(s2)
+ test3(s2)
+
+
+the new @setup functions
+--------------------------------------
+
+Consider a given @setup-marked function::
+
+ @pytest.mark.setup(maxscope=SCOPE)
+ def mysetup(request, arg1, arg2, ...)
+ ...
+ request.addfinalizer(fin)
+ ...
+
+then FUNCARGSET denotes the set of (arg1, arg2, ...) funcargs and
+all of its dependent funcargs. The mysetup function will execute
+for any matching test item once per scope.
+
+The scope is determined as the minimum scope of all scopes of the args
+in FUNCARGSET and the given "maxscope".
+
+If mysetup has been called and no finalizers have been called it is
+called "active".
+
+Furthermore the following rules apply:
+
+- if an arg value in FUNCARGSET is about to be torn down, the
+ mysetup-registered finalizers will execute as well.
+
+- There will never be two active mysetup invocations.
+
+Example 1, session scope::
+
+ @pytest.mark.funcarg(scope="session", params=[1,2])
+ def db(request):
+ request.addfinalizer(db_finalize)
+
+ @pytest.mark.setup
+ def mysetup(request, db):
+ request.addfinalizer(mysetup_finalize)
+ ...
+
+And a given test module:
+
+ def test_something():
+ ...
+ def test_otherthing():
+ pass
+
+Here is what happens::
+
+ db(request) executes with request.param == 1
+ mysetup(request, db) executes
+ test_something() executes
+ test_otherthing() executes
+ mysetup_finalize() executes
+ db_finalize() executes
+ db(request) executes with request.param == 2
+ mysetup(request, db) executes
+ test_something() executes
+ test_otherthing() executes
+ mysetup_finalize() executes
+ db_finalize() executes
+
+Example 2, session/function scope::
+
+ @pytest.mark.funcarg(scope="session", params=[1,2])
+ def db(request):
+ request.addfinalizer(db_finalize)
+
+ @pytest.mark.setup(scope="function")
+ def mysetup(request, db):
+ ...
+ request.addfinalizer(mysetup_finalize)
+ ...
+
+And a given test module:
+
+ def test_something():
+ ...
+ def test_otherthing():
+ pass
+
+Here is what happens::
+
+ db(request) executes with request.param == 1
+ mysetup(request, db) executes
+ test_something() executes
+ mysetup_finalize() executes
+ mysetup(request, db) executes
+ test_otherthing() executes
+ mysetup_finalize() executes
+ db_finalize() executes
+ db(request) executes with request.param == 2
+ mysetup(request, db) executes
+ test_something() executes
+ mysetup_finalize() executes
+ mysetup(request, db) executes
+ test_otherthing() executes
+ mysetup_finalize() executes
+ db_finalize() executes
+
+
+Example 3 - funcargs session-mix
+----------------------------------------
+
+Similar with funcargs, an example::
+
+ @pytest.mark.funcarg(scope="session", params=[1,2])
+ def db(request):
+ request.addfinalizer(db_finalize)
+
+ @pytest.mark.funcarg(scope="function")
+ def table(request, db):
+ ...
+ request.addfinalizer(table_finalize)
+ ...
+
+And a given test module:
+
+ def test_something(table):
+ ...
+ def test_otherthing(table):
+ pass
+ def test_thirdthing():
+ pass
+
+Here is what happens::
+
+ db(request) executes with param == 1
+ table(request, db)
+ test_something(table)
+ table_finalize()
+ table(request, db)
+ test_otherthing(table)
+ table_finalize()
+ db_finalize
+ db(request) executes with param == 2
+ table(request, db)
+ test_something(table)
+ table_finalize()
+ table(request, db)
+ test_otherthing(table)
+ table_finalize()
+ db_finalize
+ test_thirdthing()
+
+Data structures
+--------------------
+
+pytest internally maintains a dict of active funcargs with cache, param,
+finalizer, (scopeitem?) information:
+
+ active_funcargs = dict()
+
+if a parametrized "db" is activated:
+
+ active_funcargs["db"] = FuncargInfo(dbvalue, paramindex,
+ FuncargFinalize(...), scopeitem)
+
+if a test is torn down and the next test requires a differently
+parametrized "db":
+
+ for argname in item.callspec.params:
+ if argname in active_funcargs:
+ funcarginfo = active_funcargs[argname]
+ if funcarginfo.param != item.callspec.params[argname]:
+ funcarginfo.callfinalizer()
+ del node2funcarg[funcarginfo.scopeitem]
+ del active_funcargs[argname]
+ nodes_to_be_torn_down = ...
+ for node in nodes_to_be_torn_down:
+ if node in node2funcarg:
+ argname = node2funcarg[node]
+ active_funcargs[argname].callfinalizer()
+ del node2funcarg[node]
+ del active_funcargs[argname]
+
+if a test is setup requiring a "db" funcarg:
+
+ if "db" in active_funcargs:
+ return active_funcargs["db"][0]
+ funcarginfo = setup_funcarg()
+ active_funcargs["db"] = funcarginfo
+ node2funcarg[funcarginfo.scopeitem] = "db"
+
+Implementation plan for resources
+------------------------------------------
+
+1. Revert FuncargRequest to the old form, unmerge item/request
+ (done)
+2. make funcarg factories be discovered at collection time
+3. Introduce funcarg marker
+4. Introduce funcarg scope parameter
+5. Introduce funcarg parametrize parameter
+6. make setup functions be discovered at collection time
+7. (Introduce a pytest_fixture_protocol/setup_funcargs hook)
+
+methods and data structures
+--------------------------------
+
+A FuncarcManager holds all information about funcarg definitions
+including parametrization and scope definitions. It implements
+a pytest_generate_tests hook which performs parametrization as appropriate.
+
+as a simple example, let's consider a tree where a test function requires
+a "abc" funcarg and its factory defines it as parametrized and scoped
+for Modules. When collections hits the function item, it creates
+the metafunc object, and calls funcargdb.pytest_generate_tests(metafunc)
+which looks up available funcarg factories and their scope and parametrization.
+This information is equivalent to what can be provided today directly
+at the function site and it should thus be relatively straight forward
+to implement the additional way of defining parametrization/scoping.
+
+conftest loading:
+ each funcarg-factory will populate the session.funcargmanager
+
+When a test item is collected, it grows a dictionary
+(funcargname2factorycalllist). A factory lookup is performed
+for each required funcarg. The resulting factory call is stored
+with the item. If a function is parametrized multiple items are
+created with respective factory calls. Else if a factory is parametrized
+multiple items and calls to the factory function are created as well.
+
+At setup time, an item populates a funcargs mapping, mapping names
+to values. If a value is funcarg factories are queried for a given item
+test functions and setup functions are put in a class
+which looks up required funcarg factories.
+
+
diff --git a/_pytest/main.py b/_pytest/main.py
index 480810c..e6f679a 100644
--- a/_pytest/main.py
+++ b/_pytest/main.py
@@ -168,14 +168,13 @@ def pytest_runtestloop(session):
def pytest_ignore_collect(path, config):
- p = path.dirpath()
- ignore_paths = config._getconftest_pathlist("collect_ignore", path=p)
+ ignore_paths = config._getconftest_pathlist("collect_ignore", path=path.dirpath())
ignore_paths = ignore_paths or []
excludeopt = config.getoption("ignore")
if excludeopt:
ignore_paths.extend([py.path.local(x) for x in excludeopt])
- if path in ignore_paths:
+ if py.path.local(path) in ignore_paths:
return True
# Skip duplicate paths.
@@ -763,7 +762,11 @@ class Session(FSCollector):
if not has_matched and len(rep.result) == 1 and x.name == "()":
nextnames.insert(0, name)
resultnodes.extend(self.matchnodes([x], nextnames))
- node.ihook.pytest_collectreport(report=rep)
+ else:
+ # report collection failures here to avoid failing to run some test
+ # specified in the command line because the module could not be
+ # imported (#134)
+ node.ihook.pytest_collectreport(report=rep)
return resultnodes
def genitems(self, node):
diff --git a/_pytest/recwarn.py b/_pytest/recwarn.py
index 7ad6fef..9cc404a 100644
--- a/_pytest/recwarn.py
+++ b/_pytest/recwarn.py
@@ -27,10 +27,8 @@ def recwarn():
def deprecated_call(func=None, *args, **kwargs):
- """ assert that calling ``func(*args, **kwargs)`` triggers a
- ``DeprecationWarning`` or ``PendingDeprecationWarning``.
-
- This function can be used as a context manager::
+ """context manager that can be used to ensure a block of code triggers a
+ ``DeprecationWarning`` or ``PendingDeprecationWarning``::
>>> import warnings
>>> def api_call_v2():
@@ -40,38 +38,47 @@ def deprecated_call(func=None, *args, **kwargs):
>>> with deprecated_call():
... assert api_call_v2() == 200
- Note: we cannot use WarningsRecorder here because it is still subject
- to the mechanism that prevents warnings of the same type from being
- triggered twice for the same module. See #1190.
+ ``deprecated_call`` can also be used by passing a function and ``*args`` and ``*kwargs``,
+ in which case it will ensure calling ``func(*args, **kwargs)`` produces one of the warnings
+ types above.
"""
if not func:
- return WarningsChecker(expected_warning=(DeprecationWarning, PendingDeprecationWarning))
+ return _DeprecatedCallContext()
+ else:
+ __tracebackhide__ = True
+ with _DeprecatedCallContext():
+ return func(*args, **kwargs)
- categories = []
- def warn_explicit(message, category, *args, **kwargs):
- categories.append(category)
+class _DeprecatedCallContext(object):
+ """Implements the logic to capture deprecation warnings as a context manager."""
- def warn(message, category=None, *args, **kwargs):
+ def __enter__(self):
+ self._captured_categories = []
+ self._old_warn = warnings.warn
+ self._old_warn_explicit = warnings.warn_explicit
+ warnings.warn_explicit = self._warn_explicit
+ warnings.warn = self._warn
+
+ def _warn_explicit(self, message, category, *args, **kwargs):
+ self._captured_categories.append(category)
+
+ def _warn(self, message, category=None, *args, **kwargs):
if isinstance(message, Warning):
- categories.append(message.__class__)
+ self._captured_categories.append(message.__class__)
else:
- categories.append(category)
-
- old_warn = warnings.warn
- old_warn_explicit = warnings.warn_explicit
- warnings.warn_explicit = warn_explicit
- warnings.warn = warn
- try:
- ret = func(*args, **kwargs)
- finally:
- warnings.warn_explicit = old_warn_explicit
- warnings.warn = old_warn
- deprecation_categories = (DeprecationWarning, PendingDeprecationWarning)
- if not any(issubclass(c, deprecation_categories) for c in categories):
- __tracebackhide__ = True
- raise AssertionError("%r did not produce DeprecationWarning" % (func,))
- return ret
+ self._captured_categories.append(category)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ warnings.warn_explicit = self._old_warn_explicit
+ warnings.warn = self._old_warn
+
+ if exc_type is None:
+ deprecation_categories = (DeprecationWarning, PendingDeprecationWarning)
+ if not any(issubclass(c, deprecation_categories) for c in self._captured_categories):
+ __tracebackhide__ = True
+ msg = "Did not produce DeprecationWarning or PendingDeprecationWarning"
+ raise AssertionError(msg)
def warns(expected_warning, *args, **kwargs):
diff --git a/_pytest/terminal.py b/_pytest/terminal.py
index e226d60..af89d0f 100644
--- a/_pytest/terminal.py
+++ b/_pytest/terminal.py
@@ -282,7 +282,7 @@ class TerminalReporter:
line = "collected "
else:
line = "collecting "
- line += str(self._numcollected) + " items"
+ line += str(self._numcollected) + " item" + ('' if self._numcollected == 1 else 's')
if errors:
line += " / %d errors" % errors
if skipped:
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..cc72b4b
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,42 @@
+environment:
+ COVERALLS_REPO_TOKEN:
+ secure: 2NJ5Ct55cHJ9WEg3xbSqCuv0rdgzzb6pnzOIG5OkMbTndw3wOBrXntWFoQrXiMFi
+ # this is pytest's token in coveralls.io, encrypted
+ # using pytestbot account as detailed here:
+ # https://www.appveyor.com/docs/build-configuration#secure-variables
+
+ matrix:
+ # coveralls is not in the default env list
+ - TOXENV: "coveralls"
+ # note: please use "tox --listenvs" to populate the build matrix below
+ - TOXENV: "linting"
+ - TOXENV: "py26"
+ - TOXENV: "py27"
+ - TOXENV: "py33"
+ - TOXENV: "py34"
+ - TOXENV: "py35"
+ - TOXENV: "py36"
+ - TOXENV: "pypy"
+ - TOXENV: "py27-pexpect"
... 999 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pytest.git
More information about the Python-modules-commits
mailing list