Skip to content

Commit bfbb2b6

Browse files
committed
Add support for --indulgent-ordering option
This requests that the plugin be run first, allowing other plugins to override its ordering. This is useful if the order requirements provided by this plugin are intended to be priorities, rather than absolute requirements. For example, if some test cases run slower than others in your test suite, you can mark them as desirable to run first when running tests in parallel, allowing a more efficient use of a multi-core processor. By adding the `--indulgent-ordering` option, this ordering can still be overridden by, for example, the `--failed-first` option, which prioritizes tests which failed during the last run. Without `--indulgent-ordering`, the `--failed-first` option will be overridden by pytest-ordering, reducing its usefulness by increasing the total time until the results are available.
1 parent d3e5615 commit bfbb2b6

File tree

4 files changed

+70
-25
lines changed

4 files changed

+70
-25
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ Frank Tobia <[email protected]>
22
Sergei Chipiga <[email protected]>
33
Ben Greene <[email protected]>
44
Adam Talsma <[email protected]>
5+
Andrew Gilbert <[email protected]>

CHANGELOG

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
Unreleased
2+
---
3+
- #?? Add ``--indulgent-ordering`` to request that the sort from
4+
pytest-ordering be run before other plugins. This allows the built-in
5+
``--failed-first`` implementation to override the ordering.
16

27
0.6
38
---

docs/source/index.rst

+15
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,21 @@ You can also use markers such as "first", "second", "last", and "second_to_last"
114114

115115
=========================== 4 passed in 0.02 seconds ===========================
116116

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

118133
Aspirational
119134
============

pytest_ordering/__init__.py

+49-25
Original file line numberDiff line numberDiff line change
@@ -26,47 +26,71 @@
2626

2727

2828
def pytest_configure(config):
29-
"""Register the "run" marker."""
29+
"""Register the "run" marker and configur the plugin depending on the CLI
30+
options"""
3031

3132
config_line = (
3233
'run: specify ordering information for when tests should run '
3334
'in relation to one another. Provided by pytest-ordering. '
3435
'See also: http://pytest-ordering.readthedocs.org/'
3536
)
3637
config.addinivalue_line('markers', config_line)
38+
if config.getoption('indulgent-ordering'):
39+
# We need to dynamically add this `tryfirst` decorator to the plugin:
40+
# only when the CLI option is present should the decorator be added.
41+
# Thus, we manually run the decorator on the class function and
42+
# manually replace it.
43+
OrderingPlugin.pytest_collection_modifyitems = pytest.hookimpl(
44+
function=OrderingPlugin.pytest_collection_modifyitems, tryfirst=True)
45+
config.pluginmanager.register(OrderingPlugin(), 'orderingplugin')
3746

3847

39-
def pytest_collection_modifyitems(session, config, items):
40-
grouped_items = {}
48+
def pytest_addoption(parser):
49+
"""Set up CLI option for pytest"""
50+
group = parser.getgroup('ordering')
51+
group.addoption('--indulgent-ordering', action='store_true',
52+
dest='indulgent-ordering', help='''Request that the sort \
53+
order provided by pytest-ordering be applied before other sorting, allowing the \
54+
other sorting to have priority''')
4155

42-
for item in items:
56+
class OrderingPlugin:
57+
"""
58+
Plugin implementation
4359
44-
for mark_name, order in orders_map.items():
45-
mark = item.get_closest_marker(mark_name)
60+
By putting this in a class, we are able to dynamically register it after
61+
the CLI is parsed.
62+
"""
63+
def pytest_collection_modifyitems(session, config, items):
64+
grouped_items = {}
4665

47-
if mark:
48-
item.add_marker(pytest.mark.run(order=order))
49-
break
66+
for item in items:
67+
68+
for mark_name, order in orders_map.items():
69+
mark = item.get_closest_marker(mark_name)
5070

51-
mark = item.get_closest_marker('run')
71+
if mark:
72+
item.add_marker(pytest.mark.run(order=order))
73+
break
5274

53-
if mark:
54-
order = mark.kwargs.get('order')
55-
else:
56-
order = None
75+
mark = item.get_closest_marker('run')
76+
77+
if mark:
78+
order = mark.kwargs.get('order')
79+
else:
80+
order = None
5781

58-
grouped_items.setdefault(order, []).append(item)
82+
grouped_items.setdefault(order, []).append(item)
5983

60-
sorted_items = []
61-
unordered_items = [grouped_items.pop(None, [])]
84+
sorted_items = []
85+
unordered_items = [grouped_items.pop(None, [])]
6286

63-
start_list = sorted((i for i in grouped_items.items() if i[0] >= 0),
64-
key=operator.itemgetter(0))
65-
end_list = sorted((i for i in grouped_items.items() if i[0] < 0),
66-
key=operator.itemgetter(0))
87+
start_list = sorted((i for i in grouped_items.items() if i[0] >= 0),
88+
key=operator.itemgetter(0))
89+
end_list = sorted((i for i in grouped_items.items() if i[0] < 0),
90+
key=operator.itemgetter(0))
6791

68-
sorted_items.extend([i[1] for i in start_list])
69-
sorted_items.extend(unordered_items)
70-
sorted_items.extend([i[1] for i in end_list])
92+
sorted_items.extend([i[1] for i in start_list])
93+
sorted_items.extend(unordered_items)
94+
sorted_items.extend([i[1] for i in end_list])
7195

72-
items[:] = [item for sublist in sorted_items for item in sublist]
96+
items[:] = [item for sublist in sorted_items for item in sublist]

0 commit comments

Comments
 (0)