blacken docs

This commit is contained in:
Anthony Sottile 2018-06-02 20:29:28 -07:00
parent 5c878001ea
commit 0f2d7dc73c
18 changed files with 217 additions and 127 deletions

View File

@ -5,7 +5,13 @@ repos:
hooks: hooks:
- id: black - id: black
args: [--safe, --quiet] args: [--safe, --quiet]
python_version: python3.6 language_version: python3.6
- repo: https://github.com/asottile/blacken-docs
rev: v0.1.1
hooks:
- id: blacken-docs
additional_dependencies: [black==18.5b1]
language_version: python3.6
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v1.2.3 rev: v1.2.3
hooks: hooks:

View File

@ -40,6 +40,7 @@ An example of a simple test:
def inc(x): def inc(x):
return x + 1 return x + 1
def test_answer(): def test_answer():
assert inc(3) == 5 assert inc(3) == 5

View File

@ -145,9 +145,9 @@ as a context manager, disabling capture inside the ``with`` block:
.. code-block:: python .. code-block:: python
def test_disabling_capturing(capsys): def test_disabling_capturing(capsys):
print('this output is captured') print("this output is captured")
with capsys.disabled(): with capsys.disabled():
print('output not captured, going directly to sys.stdout') print("output not captured, going directly to sys.stdout")
print('this output is also captured') print("this output is also captured")
.. include:: links.inc .. include:: links.inc

View File

@ -9,15 +9,18 @@ example: specifying and selecting acceptance tests
# ./conftest.py # ./conftest.py
def pytest_option(parser): def pytest_option(parser):
group = parser.getgroup("myproject") group = parser.getgroup("myproject")
group.addoption("-A", dest="acceptance", action="store_true", group.addoption(
help="run (slow) acceptance tests") "-A", dest="acceptance", action="store_true", help="run (slow) acceptance tests"
)
def pytest_funcarg__accept(request): def pytest_funcarg__accept(request):
return AcceptFixture(request) return AcceptFixture(request)
class AcceptFixture(object): class AcceptFixture(object):
def __init__(self, request): def __init__(self, request):
if not request.config.getoption('acceptance'): if not request.config.getoption("acceptance"):
pytest.skip("specify -A to run acceptance tests") pytest.skip("specify -A to run acceptance tests")
self.tmpdir = request.config.mktemp(request.function.__name__, numbered=True) self.tmpdir = request.config.mktemp(request.function.__name__, numbered=True)
@ -61,6 +64,7 @@ extend the `accept example`_ by putting this in our test module:
arg.tmpdir.mkdir("special") arg.tmpdir.mkdir("special")
return arg return arg
class TestSpecialAcceptance(object): class TestSpecialAcceptance(object):
def test_sometest(self, accept): def test_sometest(self, accept):
assert accept.tmpdir.join("special").check() assert accept.tmpdir.join("special").check()

View File

@ -32,9 +32,12 @@ provide the ``cmdopt`` through a :ref:`fixture function <fixture function>`:
# content of conftest.py # content of conftest.py
import pytest import pytest
def pytest_addoption(parser): def pytest_addoption(parser):
parser.addoption("--cmdopt", action="store", default="type1", parser.addoption(
help="my option: type1 or type2") "--cmdopt", action="store", default="type1", help="my option: type1 or type2"
)
@pytest.fixture @pytest.fixture
def cmdopt(request): def cmdopt(request):
@ -102,9 +105,12 @@ the command line arguments before they get processed:
# content of conftest.py # content of conftest.py
import sys import sys
def pytest_load_initial_conftests(args): def pytest_load_initial_conftests(args):
if 'xdist' in sys.modules: # pytest-xdist plugin if "xdist" in sys.modules: # pytest-xdist plugin
import multiprocessing import multiprocessing
num = max(multiprocessing.cpu_count() / 2, 1) num = max(multiprocessing.cpu_count() / 2, 1)
args[:] = ["-n", str(num)] + args args[:] = ["-n", str(num)] + args
@ -136,9 +142,13 @@ line option to control skipping of ``pytest.mark.slow`` marked tests:
# content of conftest.py # content of conftest.py
import pytest import pytest
def pytest_addoption(parser): def pytest_addoption(parser):
parser.addoption("--runslow", action="store_true", parser.addoption(
default=False, help="run slow tests") "--runslow", action="store_true", default=False, help="run slow tests"
)
def pytest_collection_modifyitems(config, items): def pytest_collection_modifyitems(config, items):
if config.getoption("--runslow"): if config.getoption("--runslow"):
@ -206,11 +216,14 @@ Example:
# content of test_checkconfig.py # content of test_checkconfig.py
import pytest import pytest
def checkconfig(x): def checkconfig(x):
__tracebackhide__ = True __tracebackhide__ = True
if not hasattr(x, "config"): if not hasattr(x, "config"):
pytest.fail("not configured: %s" % (x,)) pytest.fail("not configured: %s" % (x,))
def test_something(): def test_something():
checkconfig(42) checkconfig(42)
@ -240,14 +253,17 @@ this to make sure unexpected exception types aren't hidden:
import operator import operator
import pytest import pytest
class ConfigException(Exception): class ConfigException(Exception):
pass pass
def checkconfig(x): def checkconfig(x):
__tracebackhide__ = operator.methodcaller('errisinstance', ConfigException) __tracebackhide__ = operator.methodcaller("errisinstance", ConfigException)
if not hasattr(x, "config"): if not hasattr(x, "config"):
raise ConfigException("not configured: %s" % (x,)) raise ConfigException("not configured: %s" % (x,))
def test_something(): def test_something():
checkconfig(42) checkconfig(42)
@ -269,19 +285,23 @@ running from a test you can do something like this:
# content of conftest.py # content of conftest.py
def pytest_configure(config): def pytest_configure(config):
import sys import sys
sys._called_from_test = True sys._called_from_test = True
def pytest_unconfigure(config): def pytest_unconfigure(config):
import sys import sys
del sys._called_from_test del sys._called_from_test
and then check for the ``sys._called_from_test`` flag: and then check for the ``sys._called_from_test`` flag:
.. code-block:: python .. code-block:: python
if hasattr(sys, '_called_from_test'): if hasattr(sys, "_called_from_test"):
# called from within a test run # called from within a test run
... ...
else: else:
@ -303,6 +323,7 @@ It's easy to present extra information in a ``pytest`` run:
# content of conftest.py # content of conftest.py
def pytest_report_header(config): def pytest_report_header(config):
return "project deps: mylib-1.1" return "project deps: mylib-1.1"
@ -327,8 +348,9 @@ display more information if applicable:
# content of conftest.py # content of conftest.py
def pytest_report_header(config): def pytest_report_header(config):
if config.getoption('verbose') > 0: if config.getoption("verbose") > 0:
return ["info1: did you know that ...", "did you?"] return ["info1: did you know that ...", "did you?"]
which will add info only when run with "--v":: which will add info only when run with "--v"::
@ -369,12 +391,15 @@ out which tests are the slowest. Let's make an artificial test suite:
# content of test_some_are_slow.py # content of test_some_are_slow.py
import time import time
def test_funcfast(): def test_funcfast():
time.sleep(0.1) time.sleep(0.1)
def test_funcslow1(): def test_funcslow1():
time.sleep(0.2) time.sleep(0.2)
def test_funcslow2(): def test_funcslow2():
time.sleep(0.3) time.sleep(0.3)
@ -411,12 +436,14 @@ an ``incremental`` marker which is to be used on classes:
import pytest import pytest
def pytest_runtest_makereport(item, call): def pytest_runtest_makereport(item, call):
if "incremental" in item.keywords: if "incremental" in item.keywords:
if call.excinfo is not None: if call.excinfo is not None:
parent = item.parent parent = item.parent
parent._previousfailed = item parent._previousfailed = item
def pytest_runtest_setup(item): def pytest_runtest_setup(item):
if "incremental" in item.keywords: if "incremental" in item.keywords:
previousfailed = getattr(item.parent, "_previousfailed", None) previousfailed = getattr(item.parent, "_previousfailed", None)
@ -432,15 +459,19 @@ tests in a class. Here is a test module example:
import pytest import pytest
@pytest.mark.incremental @pytest.mark.incremental
class TestUserHandling(object): class TestUserHandling(object):
def test_login(self): def test_login(self):
pass pass
def test_modification(self): def test_modification(self):
assert 0 assert 0
def test_deletion(self): def test_deletion(self):
pass pass
def test_normal(): def test_normal():
pass pass
@ -491,9 +522,11 @@ Here is an example for making a ``db`` fixture available in a directory:
# content of a/conftest.py # content of a/conftest.py
import pytest import pytest
class DB(object): class DB(object):
pass pass
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def db(): def db():
return DB() return DB()
@ -602,6 +635,7 @@ case we just write some information out to a ``failures`` file:
import pytest import pytest
import os.path import os.path
@pytest.hookimpl(tryfirst=True, hookwrapper=True) @pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call): def pytest_runtest_makereport(item, call):
# execute all other hooks to obtain the report object # execute all other hooks to obtain the report object
@ -628,6 +662,8 @@ if you then have failing tests:
# content of test_module.py # content of test_module.py
def test_fail1(tmpdir): def test_fail1(tmpdir):
assert 0 assert 0
def test_fail2(): def test_fail2():
assert 0 assert 0
@ -680,6 +716,7 @@ here is a little example implemented via a local plugin:
import pytest import pytest
@pytest.hookimpl(tryfirst=True, hookwrapper=True) @pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call): def pytest_runtest_makereport(item, call):
# execute all other hooks to obtain the report object # execute all other hooks to obtain the report object
@ -712,16 +749,20 @@ if you then have failing tests:
import pytest import pytest
@pytest.fixture @pytest.fixture
def other(): def other():
assert 0 assert 0
def test_setup_fails(something, other): def test_setup_fails(something, other):
pass pass
def test_call_fails(something): def test_call_fails(something):
assert 0 assert 0
def test_fail2(): def test_fail2():
assert 0 assert 0
@ -789,7 +830,7 @@ test got stuck if necessary:
for pid in psutil.pids(): for pid in psutil.pids():
environ = psutil.Process(pid).environ() environ = psutil.Process(pid).environ()
if 'PYTEST_CURRENT_TEST' in environ: if "PYTEST_CURRENT_TEST" in environ:
print(f'pytest process {pid} running: {environ["PYTEST_CURRENT_TEST"]}') print(f'pytest process {pid} running: {environ["PYTEST_CURRENT_TEST"]}')
During the test session pytest will set ``PYTEST_CURRENT_TEST`` to the current test During the test session pytest will set ``PYTEST_CURRENT_TEST`` to the current test
@ -843,8 +884,9 @@ like ``pytest-timeout`` they must be imported explicitly and passed on to pytest
import sys import sys
import pytest_timeout # Third party plugin import pytest_timeout # Third party plugin
if len(sys.argv) > 1 and sys.argv[1] == '--pytest': if len(sys.argv) > 1 and sys.argv[1] == "--pytest":
import pytest import pytest
sys.exit(pytest.main(sys.argv[2:], plugins=[pytest_timeout])) sys.exit(pytest.main(sys.argv[2:], plugins=[pytest_timeout]))
else: else:
# normal application execution: at this point argv can be parsed # normal application execution: at this point argv can be parsed

View File

@ -275,18 +275,22 @@ Consider the code below:
def s1(): def s1():
pass pass
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def m1(): def m1():
pass pass
@pytest.fixture @pytest.fixture
def f1(tmpdir): def f1(tmpdir):
pass pass
@pytest.fixture @pytest.fixture
def f2(): def f2():
pass pass
def test_foo(f1, m1, f2, s1): def test_foo(f1, m1, f2, s1):
... ...
@ -317,6 +321,7 @@ the code after the *yield* statement serves as the teardown code:
import smtplib import smtplib
import pytest import pytest
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def smtp(): def smtp():
smtp = smtplib.SMTP("smtp.gmail.com", 587, timeout=5) smtp = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
@ -351,6 +356,7 @@ Note that we can also seamlessly use the ``yield`` syntax with ``with`` statemen
import smtplib import smtplib
import pytest import pytest
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def smtp(): def smtp():
with smtplib.SMTP("smtp.gmail.com", 587, timeout=5) as smtp: with smtplib.SMTP("smtp.gmail.com", 587, timeout=5) as smtp:
@ -376,12 +382,15 @@ Here's the ``smtp`` fixture changed to use ``addfinalizer`` for cleanup:
import smtplib import smtplib
import pytest import pytest
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def smtp(request): def smtp(request):
smtp = smtplib.SMTP("smtp.gmail.com", 587, timeout=5) smtp = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
def fin(): def fin():
print("teardown smtp") print("teardown smtp")
smtp.close() smtp.close()
request.addfinalizer(fin) request.addfinalizer(fin)
return smtp # provide the fixture value return smtp # provide the fixture value
@ -868,7 +877,8 @@ You can specify multiple fixtures like this:
.. code-block:: python .. code-block:: python
@pytest.mark.usefixtures("cleandir", "anotherfixture") @pytest.mark.usefixtures("cleandir", "anotherfixture")
def test(): ... def test():
...
and you may specify fixture usage at the test module level, using and you may specify fixture usage at the test module level, using
a generic feature of the mark mechanism: a generic feature of the mark mechanism:

View File

@ -215,8 +215,8 @@ Add this to ``setup.py`` file:
setup( setup(
# ..., # ...,
setup_requires=['pytest-runner', ...], setup_requires=["pytest-runner", ...],
tests_require=['pytest', ...], tests_require=["pytest", ...],
# ..., # ...,
) )
@ -263,24 +263,26 @@ your own setuptools Test command for invoking pytest.
class PyTest(TestCommand): class PyTest(TestCommand):
user_options = [('pytest-args=', 'a', "Arguments to pass to pytest")] user_options = [("pytest-args=", "a", "Arguments to pass to pytest")]
def initialize_options(self): def initialize_options(self):
TestCommand.initialize_options(self) TestCommand.initialize_options(self)
self.pytest_args = '' self.pytest_args = ""
def run_tests(self): def run_tests(self):
import shlex import shlex
# import here, cause outside the eggs aren't loaded # import here, cause outside the eggs aren't loaded
import pytest import pytest
errno = pytest.main(shlex.split(self.pytest_args)) errno = pytest.main(shlex.split(self.pytest_args))
sys.exit(errno) sys.exit(errno)
setup( setup(
# ..., # ...,
tests_require=['pytest'], tests_require=["pytest"],
cmdclass = {'test': PyTest}, cmdclass={"test": PyTest},
) )
Now if you run:: Now if you run::

View File

@ -17,6 +17,7 @@ An example of a simple test:
def inc(x): def inc(x):
return x + 1 return x + 1
def test_answer(): def test_answer():
assert inc(3) == 5 assert inc(3) == 5

View File

@ -138,10 +138,14 @@ the records for the ``setup`` and ``call`` stages during teardown like so:
def window(caplog): def window(caplog):
window = create_window() window = create_window()
yield window yield window
for when in ('setup', 'call'): for when in ("setup", "call"):
messages = [x.message for x in caplog.get_records(when) if x.level == logging.WARNING] messages = [
x.message for x in caplog.get_records(when) if x.level == logging.WARNING
]
if messages: if messages:
pytest.fail('warning messages encountered during testing: {}'.format(messages)) pytest.fail(
"warning messages encountered during testing: {}".format(messages)
)

View File

@ -70,12 +70,12 @@ In general there are two scenarios on how markers should be handled:
.. code-block:: python .. code-block:: python
# replace this: # replace this:
marker = item.get_marker('log_level') marker = item.get_marker("log_level")
if marker: if marker:
level = marker.args[0] level = marker.args[0]
# by this: # by this:
marker = item.get_closest_marker('log_level') marker = item.get_closest_marker("log_level")
if marker: if marker:
level = marker.args[0] level = marker.args[0]
@ -87,14 +87,14 @@ order doesn't even matter. You probably want to think of your marks as a set her
.. code-block:: python .. code-block:: python
# replace this # replace this
skipif = item.get_marker('skipif') skipif = item.get_marker("skipif")
if skipif: if skipif:
for condition in skipif.args: for condition in skipif.args:
# eval condition # eval condition
... ...
# by this: # by this:
for skipif in item.iter_markers('skipif'): for skipif in item.iter_markers("skipif"):
condition = skipif.args[0] condition = skipif.args[0]
# eval condition # eval condition

View File

@ -71,6 +71,8 @@ so that any attempts within tests to create http requests will fail.
.. code-block:: python .. code-block:: python
import functools import functools
def test_partial(monkeypatch): def test_partial(monkeypatch):
with monkeypatch.context() as m: with monkeypatch.context() as m:
m.setattr(functools, "partial", 3) m.setattr(functools, "partial", 3)

View File

@ -35,26 +35,29 @@ This is how a functional test could look like:
import pytest import pytest
@pytest.fixture @pytest.fixture
def default_context(): def default_context():
return {'extra_context': {}} return {"extra_context": {}}
@pytest.fixture(params=[ @pytest.fixture(
{'author': 'alice'}, params=[
{'project_slug': 'helloworld'}, {"author": "alice"},
{'author': 'bob', 'project_slug': 'foobar'}, {"project_slug": "helloworld"},
]) {"author": "bob", "project_slug": "foobar"},
]
)
def extra_context(request): def extra_context(request):
return {'extra_context': request.param} return {"extra_context": request.param}
@pytest.fixture(params=['default', 'extra']) @pytest.fixture(params=["default", "extra"])
def context(request): def context(request):
if request.param == 'default': if request.param == "default":
return request.getfuncargvalue('default_context') return request.getfuncargvalue("default_context")
else: else:
return request.getfuncargvalue('extra_context') return request.getfuncargvalue("extra_context")
def test_generate_project(cookies, context): def test_generate_project(cookies, context):
@ -95,8 +98,7 @@ fixtures from existing ones.
.. code-block:: python .. code-block:: python
pytest.define_combined_fixture( pytest.define_combined_fixture(
name='context', name="context", fixtures=["default_context", "extra_context"]
fixtures=['default_context', 'extra_context'],
) )
The new fixture ``context`` inherits the scope from the used fixtures and yield The new fixture ``context`` inherits the scope from the used fixtures and yield
@ -123,10 +125,12 @@ all parameters marked as a fixture.
.. code-block:: python .. code-block:: python
@pytest.fixture(params=[ @pytest.fixture(
pytest.fixture_request('default_context'), params=[
pytest.fixture_request('extra_context'), pytest.fixture_request("default_context"),
]) pytest.fixture_request("extra_context"),
]
)
def context(request): def context(request):
"""Returns all values for ``default_context``, one-by-one before it """Returns all values for ``default_context``, one-by-one before it
does the same for ``extra_context``. does the same for ``extra_context``.
@ -145,10 +149,10 @@ The same helper can be used in combination with ``pytest.mark.parametrize``.
@pytest.mark.parametrize( @pytest.mark.parametrize(
'context, expected_response_code', "context, expected_response_code",
[ [
(pytest.fixture_request('default_context'), 0), (pytest.fixture_request("default_context"), 0),
(pytest.fixture_request('extra_context'), 0), (pytest.fixture_request("extra_context"), 0),
], ],
) )
def test_generate_project(cookies, context, exit_code): def test_generate_project(cookies, context, exit_code):

View File

@ -198,7 +198,7 @@ For example:
.. code-block:: python .. code-block:: python
@pytest.mark.timeout(10, 'slow', method='thread') @pytest.mark.timeout(10, "slow", method="thread")
def test_function(): def test_function():
... ...
@ -208,8 +208,8 @@ Will create and attach a :class:`Mark <_pytest.mark.structures.Mark>` object to
.. code-block:: python .. code-block:: python
mark.args == (10, 'slow') mark.args == (10, "slow")
mark.kwargs == {'method': 'thread'} mark.kwargs == {"method": "thread"}
Fixtures Fixtures
@ -225,9 +225,9 @@ Example of a test requiring a fixture:
.. code-block:: python .. code-block:: python
def test_output(capsys): def test_output(capsys):
print('hello') print("hello")
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == 'hello\n' assert out == "hello\n"
Example of a fixture requiring another fixture: Example of a fixture requiring another fixture:
@ -236,7 +236,7 @@ Example of a fixture requiring another fixture:
@pytest.fixture @pytest.fixture
def db_session(tmpdir): def db_session(tmpdir):
fn = tmpdir / 'db.file' fn = tmpdir / "db.file"
return connect(str(fn)) return connect(str(fn))
For more details, consult the full :ref:`fixtures docs <fixture>`. For more details, consult the full :ref:`fixtures docs <fixture>`.
@ -368,7 +368,7 @@ doctest_namespace
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def add_np(doctest_namespace): def add_np(doctest_namespace):
doctest_namespace['np'] = numpy doctest_namespace["np"] = numpy
For more details: :ref:`doctest_namespace`. For more details: :ref:`doctest_namespace`.
@ -805,12 +805,14 @@ test functions and methods. Can be either a single mark or a sequence of marks.
.. code-block:: python .. code-block:: python
import pytest import pytest
pytestmark = pytest.mark.webtest pytestmark = pytest.mark.webtest
.. code-block:: python .. code-block:: python
import pytest import pytest
pytestmark = (pytest.mark.integration, pytest.mark.slow) pytestmark = (pytest.mark.integration, pytest.mark.slow)
PYTEST_DONT_REWRITE (module docstring) PYTEST_DONT_REWRITE (module docstring)

View File

@ -192,19 +192,19 @@ Here's a quick guide on how to skip tests in a module in different situations:
.. code-block:: python .. code-block:: python
pytestmark = pytest.mark.skip('all tests still WIP') pytestmark = pytest.mark.skip("all tests still WIP")
2. Skip all tests in a module based on some condition: 2. Skip all tests in a module based on some condition:
.. code-block:: python .. code-block:: python
pytestmark = pytest.mark.skipif(sys.platform == 'win32', 'tests for linux only') pytestmark = pytest.mark.skipif(sys.platform == "win32", "tests for linux only")
3. Skip all tests in a module if some import is missing: 3. Skip all tests in a module if some import is missing:
.. code-block:: python .. code-block:: python
pexpect = pytest.importorskip('pexpect') pexpect = pytest.importorskip("pexpect")
.. _xfail: .. _xfail:
@ -364,14 +364,20 @@ test instances when using parametrize:
import pytest import pytest
@pytest.mark.parametrize(("n", "expected"), [
@pytest.mark.parametrize(
("n", "expected"),
[
(1, 2), (1, 2),
pytest.param(1, 0, marks=pytest.mark.xfail), pytest.param(1, 0, marks=pytest.mark.xfail),
pytest.param(1, 3, marks=pytest.mark.xfail(reason="some bug")), pytest.param(1, 3, marks=pytest.mark.xfail(reason="some bug")),
(2, 3), (2, 3),
(3, 4), (3, 4),
(4, 5), (4, 5),
pytest.param(10, 11, marks=pytest.mark.skipif(sys.version_info >= (3, 0), reason="py2k")), pytest.param(
]) 10, 11, marks=pytest.mark.skipif(sys.version_info >= (3, 0), reason="py2k")
),
],
)
def test_increment(n, expected): def test_increment(n, expected):
assert n + 1 == expected assert n + 1 == expected

View File

@ -71,13 +71,15 @@ to save time:
# contents of conftest.py # contents of conftest.py
import pytest import pytest
@pytest.fixture(scope='session')
@pytest.fixture(scope="session")
def image_file(tmpdir_factory): def image_file(tmpdir_factory):
img = compute_expensive_image() img = compute_expensive_image()
fn = tmpdir_factory.mktemp('data').join('img.png') fn = tmpdir_factory.mktemp("data").join("img.png")
img.save(str(fn)) img.save(str(fn))
return fn return fn
# contents of test_image.py # contents of test_image.py
def test_histogram(image_file): def test_histogram(image_file):
img = load_image(image_file) img = load_image(image_file)

View File

@ -272,11 +272,12 @@ Alternatively, you can integrate this functionality with custom markers:
# content of conftest.py # content of conftest.py
def pytest_collection_modifyitems(session, config, items): def pytest_collection_modifyitems(session, config, items):
for item in items: for item in items:
for marker in item.iter_markers(name='test_id'): for marker in item.iter_markers(name="test_id"):
test_id = marker.args[0] test_id = marker.args[0]
item.user_properties.append(('test_id', test_id)) item.user_properties.append(("test_id", test_id))
And in your tests: And in your tests:
@ -284,6 +285,8 @@ And in your tests:
# content of test_function.py # content of test_function.py
import pytest import pytest
@pytest.mark.test_id(1501) @pytest.mark.test_id(1501)
def test_function(): def test_function():
assert True assert True
@ -318,7 +321,7 @@ To add an additional xml attribute to a testcase element, you can use
def test_function(record_xml_attribute): def test_function(record_xml_attribute):
record_xml_attribute("assertions", "REQ-1234") record_xml_attribute("assertions", "REQ-1234")
record_xml_attribute("classname", "custom_classname") record_xml_attribute("classname", "custom_classname")
print('hello world') print("hello world")
assert True assert True
Unlike ``record_property``, this will not add a new child element. Unlike ``record_property``, this will not add a new child element.
@ -377,19 +380,22 @@ to all testcases you can use ``LogXML.add_global_properties``
import pytest import pytest
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def log_global_env_facts(f): def log_global_env_facts(f):
if pytest.config.pluginmanager.hasplugin('junitxml'): if pytest.config.pluginmanager.hasplugin("junitxml"):
my_junit = getattr(pytest.config, '_xml', None) my_junit = getattr(pytest.config, "_xml", None)
my_junit.add_global_property("ARCH", "PPC")
my_junit.add_global_property("STORAGE_TYPE", "CEPH")
my_junit.add_global_property('ARCH', 'PPC')
my_junit.add_global_property('STORAGE_TYPE', 'CEPH')
@pytest.mark.usefixtures(log_global_env_facts.__name__) @pytest.mark.usefixtures(log_global_env_facts.__name__)
def start_and_prepare_env(): def start_and_prepare_env():
pass pass
class TestMe(object): class TestMe(object):
def test_foo(self): def test_foo(self):
assert True assert True

View File

@ -94,11 +94,13 @@ even module level:
import warnings import warnings
def api_v1(): def api_v1():
warnings.warn(UserWarning("api v1, should use functions from v2")) warnings.warn(UserWarning("api v1, should use functions from v2"))
return 1 return 1
@pytest.mark.filterwarnings('ignore:api v1')
@pytest.mark.filterwarnings("ignore:api v1")
def test_one(): def test_one():
assert api_v1() == 1 assert api_v1() == 1
@ -112,7 +114,7 @@ decorator or to all tests in a module by setting the ``pytestmark`` variable:
.. code-block:: python .. code-block:: python
# turns all warnings into errors for this module # turns all warnings into errors for this module
pytestmark = pytest.mark.filterwarnings('error') pytestmark = pytest.mark.filterwarnings("error")
.. note:: .. note::

View File

@ -150,19 +150,11 @@ it in your setuptools-invocation:
setup( setup(
name="myproject", name="myproject",
packages = ['myproject'], packages=["myproject"],
# the following makes a plugin available to pytest # the following makes a plugin available to pytest
entry_points = { entry_points={"pytest11": ["name_of_plugin = myproject.pluginmodule"]},
'pytest11': [
'name_of_plugin = myproject.pluginmodule',
]
},
# custom PyPI classifier for pytest plugins # custom PyPI classifier for pytest plugins
classifiers=[ classifiers=["Framework :: Pytest"],
"Framework :: Pytest",
],
) )
If a package is installed this way, ``pytest`` will load If a package is installed this way, ``pytest`` will load
@ -213,11 +205,7 @@ With the following typical ``setup.py`` extract:
.. code-block:: python .. code-block:: python
setup( setup(..., entry_points={"pytest11": ["foo = pytest_foo.plugin"]}, ...)
...,
entry_points={'pytest11': ['foo = pytest_foo.plugin']},
...,
)
In this case only ``pytest_foo/plugin.py`` will be rewritten. If the In this case only ``pytest_foo/plugin.py`` will be rewritten. If the
helper module also contains assert statements which need to be helper module also contains assert statements which need to be
@ -232,7 +220,7 @@ import ``helper.py`` normally. The contents of
import pytest import pytest
pytest.register_assert_rewrite('pytest_foo.helper') pytest.register_assert_rewrite("pytest_foo.helper")
@ -332,23 +320,25 @@ string value of ``Hello World!`` if we do not supply a value or ``Hello
import pytest import pytest
def pytest_addoption(parser): def pytest_addoption(parser):
group = parser.getgroup('helloworld') group = parser.getgroup("helloworld")
group.addoption( group.addoption(
'--name', "--name",
action='store', action="store",
dest='name', dest="name",
default='World', default="World",
help='Default "name" for hello().' help='Default "name" for hello().',
) )
@pytest.fixture @pytest.fixture
def hello(request): def hello(request):
name = request.config.getoption('name') name = request.config.getoption("name")
def _hello(name=None): def _hello(name=None):
if not name: if not name:
name = request.config.getoption('name') name = request.config.getoption("name")
return "Hello {name}!".format(name=name) return "Hello {name}!".format(name=name)
return _hello return _hello
@ -364,7 +354,8 @@ return a result object, with which we can assert the tests' outcomes.
"""Make sure that our plugin works.""" """Make sure that our plugin works."""
# create a temporary conftest.py file # create a temporary conftest.py file
testdir.makeconftest(""" testdir.makeconftest(
"""
import pytest import pytest
@pytest.fixture(params=[ @pytest.fixture(params=[
@ -374,16 +365,19 @@ return a result object, with which we can assert the tests' outcomes.
]) ])
def name(request): def name(request):
return request.param return request.param
""") """
)
# create a temporary pytest test file # create a temporary pytest test file
testdir.makepyfile(""" testdir.makepyfile(
"""
def test_hello_default(hello): def test_hello_default(hello):
assert hello() == "Hello World!" assert hello() == "Hello World!"
def test_hello_name(hello, name): def test_hello_name(hello, name):
assert hello(name) == "Hello {0}!".format(name) assert hello(name) == "Hello {0}!".format(name)
""") """
)
# run all tests with pytest # run all tests with pytest
result = testdir.runpytest() result = testdir.runpytest()
@ -514,12 +508,14 @@ after others, i.e. the position in the ``N``-sized list of functions:
# will execute as early as possible # will execute as early as possible
... ...
# Plugin 2 # Plugin 2
@pytest.hookimpl(trylast=True) @pytest.hookimpl(trylast=True)
def pytest_collection_modifyitems(items): def pytest_collection_modifyitems(items):
# will execute as late as possible # will execute as late as possible
... ...
# Plugin 3 # Plugin 3
@pytest.hookimpl(hookwrapper=True) @pytest.hookimpl(hookwrapper=True)
def pytest_collection_modifyitems(items): def pytest_collection_modifyitems(items):