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

Add support for --indulgent-ordering option #50

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ Frank Tobia <[email protected]>
Sergei Chipiga <[email protected]>
Ben Greene <[email protected]>
Adam Talsma <[email protected]>
Andrew Gilbert <[email protected]>
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Unreleased
---
### Added
- #50 Add ``--indulgent-ordering`` to request that the sort from
pytest-ordering be run before other plugins. This allows the built-in
``--failed-first`` implementation to override the ordering.

0.6
---
Expand Down
15 changes: 15 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,21 @@ You can also use markers such as "first", "second", "last", and "second_to_last"

=========================== 4 passed in 0.02 seconds ===========================

``--indulgent-ordering`` and overriding ordering
-------------

You may sometimes find that you want to suggest an ordering of tests, while
allowing it to be overridden for good reson. For example, if you run your test
suite in parallel and have a number of tests which are particularly slow, it
might be desirable to start those tests running first, in order to optimize
your completion time. You can use the pytest-ordering plugin to inform pytest
of this. Now suppose you also want to prioritize tests which failed during the
previous run, by using the ``--failed-first`` option. By default,
pytest-ordering will override the ``--failed-first`` order, but by adding the
``--indulgent-ordering`` option, you can ask pytest to run the sort from
pytest-ordering *before* the sort from ``--failed-first``, allowing the failed
tests to be sorted to the front.


Aspirational
============
Expand Down
40 changes: 36 additions & 4 deletions pytest_ordering/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,49 @@


def pytest_configure(config):
"""Register the "run" marker."""
"""Register the "run" marker and configure the plugin depending on the CLI
options"""

config_line = (
'run: specify ordering information for when tests should run '
'in relation to one another. Provided by pytest-ordering. '
'See also: http://pytest-ordering.readthedocs.org/'
)
config.addinivalue_line('markers', config_line)


def pytest_collection_modifyitems(session, config, items):
if config.getoption('indulgent-ordering'):
# We need to dynamically add this `tryfirst` decorator to the plugin:
# only when the CLI option is present should the decorator be added.
# Thus, we manually run the decorator on the class function and
# manually replace it.
# Python 2.7 didn't allow arbitrary attributes on methods, so we have
# to keep the function as a function and then add it to the class as a
# pseudomethod. Since the class is purely for structuring and `self`
# is never referenced, this seems reasonable.
OrderingPlugin.pytest_collection_modifyitems = pytest.hookimpl(
function=modify_items, tryfirst=True)
else:
OrderingPlugin.pytest_collection_modifyitems = pytest.hookimpl(
function=modify_items, trylast=True)
config.pluginmanager.register(OrderingPlugin(), 'orderingplugin')


def pytest_addoption(parser):
"""Set up CLI option for pytest"""
group = parser.getgroup('ordering')
group.addoption('--indulgent-ordering', action='store_true',
dest='indulgent-ordering', help='''Request that the sort \
order provided by pytest-ordering be applied before other sorting, allowing the \
other sorting to have priority''')

class OrderingPlugin(object):
"""
Plugin implementation

By putting this in a class, we are able to dynamically register it after
the CLI is parsed.
"""

def modify_items(session, config, items):
grouped_items = {}

for item in items:
Expand Down
40 changes: 40 additions & 0 deletions tests/test_indulgent_ordering.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
import re

import pytest
import pytest_ordering

pytest_plugins = ["pytester"]


def test_run_marker_registered(capsys, tmpdir):
testname = str(tmpdir.join("failing.py"))
with open(testname, "w") as fi:
fi.write(
"""
import pytest

@pytest.mark.second
def test_me_second():
assert True

def test_that_fails():
assert False

@pytest.mark.first
def test_me_first():
assert True
"""
)
args = ["--quiet", "--color=no", testname]
pytest.main(args, [pytest_ordering])
out, err = capsys.readouterr()
assert "..F" in out
args.insert(0, "--ff")
pytest.main(args, [pytest_ordering])
out, err = capsys.readouterr()
assert "..F" in out
args.insert(0, "--indulgent-ordering")
pytest.main(args, [pytest_ordering])
out, err = capsys.readouterr()
assert "F.." in out
2 changes: 1 addition & 1 deletion tests/test_ordering.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,6 @@ def test_5(self): pass


def test_run_marker_registered(capsys):
pytest.main('--markers')
pytest.main(['--markers'])
out, err = capsys.readouterr()
assert '@pytest.mark.run' in out