Skip to content

Commit f6fd6e7

Browse files
committed
Fix handling of combined index and dependency attributes
- could cause duplicated entries - add ``index`` keyword for ordering as alternative to raw number - refactor some tests to avoid writing test files where possible - remove support for pytest 3.6 (too many exceptions)
1 parent 170990d commit f6fd6e7

File tree

12 files changed

+276
-145
lines changed

12 files changed

+276
-145
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
### Changes
6+
- removed support for pytest 3.6 (it still may work, just isn't tested anymore)
7+
58
### Added
69
- added configuration option for sparse sorting, e.g. the possibility to
710
fill gaps between ordinals with unordered tests (see also
@@ -11,6 +14,10 @@
1114
`pytest-dependency` plugin
1215
- experimental: added configuration option for ordering all dependencies
1316
defined by the `pytest-dependency` plugin
17+
- added ``index`` keyword for ordering as alternative to raw number
18+
19+
### Fixed
20+
- correctly handle combined index and dependency attributes
1421

1522
### Infrastructure
1623
- added list of open issues in `pytest-ordering` with respective state

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ your tests are run. It uses the marker `order` that defines when a specific
88
test shall be run relative to the other tests.
99

1010
`pytest-order` works with Python 2.7 and 3.5 - 3.9, with pytest
11-
versions >= 3.6.0, and runs on Linux, MacOs and Windows.
11+
versions >= 3.7.0, and runs on Linux, MacOs and Windows.
1212

1313

1414
Documentation

docs/source/index.rst

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Here are examples for which markers correspond to markers in
3535
Supported Python and pytest versions
3636
------------------------------------
3737
``pytest-order`` supports python 2.7, 3.5 - 3.9, and pypy/pypy3, and is
38-
compatible with pytest 3.6.0 or newer. Note that support for Python 2 will
38+
compatible with pytest 3.7.0 or newer. Note that support for Python 2 will
3939
be removed in one of the next versions.
4040

4141
All supported combinations of Python and pytest versions are tested in
@@ -124,10 +124,14 @@ The above is a trivial example, but ordering is respected across test files.
124124

125125
There are currently three possibilities to define the order:
126126

127-
Order by number
128-
---------------
129-
As already shown above, the order can be defined using ordinal numbers.
130-
Negative numbers are also allowed--they are used the same way as indexes
127+
Order by index
128+
--------------
129+
As already shown above, the order can be defined using the ordinal numbers.
130+
There is a long form that uses the keyword ``index``, and a short form, that
131+
uses just the ordinal number--both are shown in the example below. The long
132+
form may be better readable if you want to combine it with a dependency marker
133+
(``before`` or ``after``, see below).
134+
Negative numbers are also allowed--they are used the same way as indices
131135
are used in Python lists, e.g. to count from the end:
132136

133137
.. code:: python
@@ -138,11 +142,11 @@ are used in Python lists, e.g. to count from the end:
138142
def test_three():
139143
assert True
140144
141-
@pytest.mark.order(-1)
145+
@pytest.mark.order(index=-1)
142146
def test_four():
143147
assert True
144148
145-
@pytest.mark.order(2)
149+
@pytest.mark.order(index=2)
146150
def test_two():
147151
assert True
148152

pytest_order/__init__.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ def mark_binning(item, keys, start, end, before, after, unordered, alias):
139139
if "order" in keys:
140140
mark = item.get_closest_marker("order")
141141
order = mark.args[0] if mark.args else None
142+
if order is None:
143+
order = mark.kwargs.get("index")
142144
before_mark = mark.kwargs.get("before")
143145
after_mark = mark.kwargs.get("after")
144146
if order is not None:
@@ -176,23 +178,36 @@ def insert_before(name, items, sort):
176178
prefix = get_filename(item)
177179
item_name = prefix + "." + item.location[2]
178180
if re.match(regex_name, item_name):
179-
if pos == 0:
180-
sort[:] = items + sort
181-
else:
182-
sort[pos:1] = items
181+
for item_to_insert in items:
182+
if item_to_insert in sort:
183+
index = sort.index(item_to_insert)
184+
if index > pos:
185+
del sort[index]
186+
sort.insert(pos, item_to_insert)
187+
else:
188+
if pos == 0:
189+
sort[:] = items + sort
190+
else:
191+
sort[pos:1] = items
183192
return True
184193
return False
185194

186195

187196
def insert_after(name, items, sort):
188197
regex_name = re.escape(name) + r"(:?\.\w+)?$"
189198
for pos, item in reversed(list(enumerate(sort))):
190-
prefix = get_filename(item)
191-
item_name = prefix + "." + item.location[2]
199+
item_name = get_filename(item) + "." + item.location[2]
192200
if re.match(regex_name, item_name):
193-
sort[pos + 1:1] = items
201+
for item_to_insert in items:
202+
if item_to_insert in sort:
203+
index = sort.index(item_to_insert)
204+
if index < pos + 1:
205+
del sort[index]
206+
pos -= 1
207+
sort.insert(pos + 1, item_to_insert)
208+
else:
209+
sort[pos + 1:1] = items
194210
return True
195-
196211
return False
197212

198213

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"pytest_order = pytest_order",
2727
]
2828
},
29-
install_requires=["pytest>=3.6"],
29+
install_requires=["pytest>=3.7"],
3030
classifiers=[
3131
"Development Status :: 4 - Beta",
3232
"Intended Audience :: Developers",

tests/conftest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,9 @@ def test_path(tmpdir):
2222
path = tmpdir.join("{}.py".format(str(uuid.uuid4())))
2323
yield str(path)
2424
path.remove()
25+
26+
27+
@pytest.fixture
28+
def ignore_settings(mocker):
29+
mocker.patch("pytest_order.Settings.initialize")
30+
yield

tests/test_dependency.py

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@
33
import pytest
44

55
import pytest_order
6-
from utils import write_test, assert_test_order
76

87

9-
def test_ignore_order_with_dependency(test_path, capsys):
8+
@pytest.fixture
9+
def order_dependencies(ignore_settings):
10+
pytest_order.Settings.order_dependencies = True
11+
yield
12+
pytest_order.Settings.order_dependencies = False
13+
14+
15+
def test_ignore_order_with_dependency(item_names_for):
1016
tests_content = """
1117
import pytest
1218
@@ -18,13 +24,10 @@ def test_a():
1824
def test_b():
1925
pass
2026
"""
21-
write_test(test_path, tests_content)
22-
pytest.main(["-v", test_path], [pytest_order])
23-
out, err = capsys.readouterr()
24-
assert_test_order(["test_a", "test_b"], out)
27+
assert item_names_for(tests_content) == ["test_a", "test_b"]
2528

2629

27-
def test_order_with_dependency(test_path, capsys):
30+
def test_order_with_dependency(item_names_for):
2831
tests_content = """
2932
import pytest
3033
@@ -36,14 +39,12 @@ def test_a():
3639
def test_b():
3740
pass
3841
"""
39-
write_test(test_path, tests_content)
40-
pytest.main(["-v", test_path], [pytest_order])
41-
out, err = capsys.readouterr()
42-
assert_test_order(["test_b", "test_a"], out)
42+
assert item_names_for(tests_content) == ["test_b", "test_a"]
4343

4444

45-
def test_dependency_already_ordered(test_path, capsys):
46-
tests_content = """
45+
@pytest.fixture(scope="module")
46+
def ordered_test():
47+
yield """
4748
import pytest
4849
4950
def test_a():
@@ -53,17 +54,21 @@ def test_a():
5354
def test_b():
5455
pass
5556
"""
56-
write_test(test_path, tests_content)
57-
pytest.main(["-v", test_path], [pytest_order])
58-
out, err = capsys.readouterr()
59-
assert_test_order(["test_a", "test_b"], out)
60-
pytest.main(["-v", "--order-dependencies", test_path], [pytest_order])
61-
out, err = capsys.readouterr()
62-
assert_test_order(["test_a", "test_b"], out)
6357

6458

65-
def test_order_dependency(test_path, capsys):
66-
tests_content = """
59+
def test_dependency_already_ordered_default(ordered_test, item_names_for):
60+
assert item_names_for(ordered_test) == ["test_a", "test_b"]
61+
62+
63+
def test_dependency_already_ordered_with_ordering(ordered_test,
64+
item_names_for,
65+
order_dependencies):
66+
assert item_names_for(ordered_test) == ["test_a", "test_b"]
67+
68+
69+
@pytest.fixture(scope="module")
70+
def order_dependency_test():
71+
yield """
6772
import pytest
6873
6974
@pytest.mark.dependency(depends=['test_b'])
@@ -73,17 +78,20 @@ def test_a():
7378
def test_b():
7479
pass
7580
"""
76-
write_test(test_path, tests_content)
77-
pytest.main(["-v", test_path], [pytest_order])
78-
out, err = capsys.readouterr()
79-
assert_test_order(["test_a", "test_b"], out)
80-
pytest.main(["-v", "--order-dependencies", test_path], [pytest_order])
81-
out, err = capsys.readouterr()
82-
assert_test_order(["test_b", "test_a"], out)
8381

8482

85-
def test_order_multiple_dependencies(test_path, capsys):
86-
tests_content = """
83+
def test_order_dependency_default(order_dependency_test, item_names_for):
84+
assert item_names_for(order_dependency_test) == ["test_a", "test_b"]
85+
86+
87+
def test_order_dependency_ordered(order_dependency_test, item_names_for,
88+
order_dependencies):
89+
assert item_names_for(order_dependency_test) == ["test_b", "test_a"]
90+
91+
92+
@pytest.fixture(scope="module")
93+
def multiple_dependencies_test():
94+
yield """
8795
import pytest
8896
8997
@pytest.mark.dependency(depends=["test_b", "test_c"])
@@ -96,17 +104,26 @@ def test_b():
96104
def test_c():
97105
pass
98106
"""
99-
write_test(test_path, tests_content)
100-
pytest.main(["-v", test_path], [pytest_order])
101-
out, err = capsys.readouterr()
102-
assert_test_order(["test_a", "test_b", "test_c"], out)
103-
pytest.main(["-v", "--order-dependencies", test_path], [pytest_order])
104-
out, err = capsys.readouterr()
105-
assert_test_order(["test_b", "test_c", "test_a"], out)
106107

107108

108-
def test_order_named_dependency(test_path, capsys):
109-
tests_content = """
109+
def test_order_multiple_dependencies_default(multiple_dependencies_test,
110+
item_names_for):
111+
assert item_names_for(multiple_dependencies_test) == [
112+
"test_a", "test_b", "test_c"
113+
]
114+
115+
116+
def test_order_multiple_dependencies_ordered(multiple_dependencies_test,
117+
item_names_for,
118+
order_dependencies):
119+
assert item_names_for(multiple_dependencies_test) == [
120+
"test_b", "test_c", "test_a"
121+
]
122+
123+
124+
@pytest.fixture(scope="module")
125+
def named_dependency_test():
126+
yield """
110127
import pytest
111128
112129
@pytest.mark.dependency(depends=["my_test"])
@@ -120,10 +137,16 @@ def test_b():
120137
def test_c():
121138
pass
122139
"""
123-
write_test(test_path, tests_content)
124-
pytest.main(["-v", test_path], [pytest_order])
125-
out, err = capsys.readouterr()
126-
assert_test_order(["test_a", "test_b", "test_c"], out)
127-
pytest.main(["-v", "--order-dependencies", test_path], [pytest_order])
128-
out, err = capsys.readouterr()
129-
assert_test_order(["test_b", "test_a", "test_c"], out)
140+
141+
142+
def test_order_named_dependency_default(named_dependency_test, item_names_for):
143+
assert item_names_for(named_dependency_test) == [
144+
"test_a", "test_b", "test_c"
145+
]
146+
147+
148+
def test_order_named_dependency_ordered(named_dependency_test,
149+
item_names_for, order_dependencies):
150+
assert item_names_for(named_dependency_test) == [
151+
"test_b", "test_a", "test_c"
152+
]

tests/test_order_scope.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def test_class_scope(fixture_path, capsys):
164164
assert_test_order(expected, out)
165165

166166

167-
@pytest.mark.skipif(pytest.__version__.startswith(("3.6.", "3.7.")),
167+
@pytest.mark.skipif(pytest.__version__.startswith("3.7."),
168168
reason="Warning does not appear in output in pytest < 3.8")
169169
def test_invalid_scope(fixture_path, capsys):
170170
args = ["-v", "--order-scope=function", fixture_path]

tests/test_ordering.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ def test_3(): pass
7272
assert item_names_for(tests_content) == ["test_3", "test_2", "test_1"]
7373

7474

75+
def test_order_marks_by_index(item_names_for):
76+
tests_content = """
77+
import pytest
78+
79+
@pytest.mark.order(index=-1)
80+
def test_1(): pass
81+
82+
@pytest.mark.order(index=-2)
83+
def test_2(): pass
84+
85+
@pytest.mark.order(index=1)
86+
def test_3(): pass
87+
"""
88+
89+
assert item_names_for(tests_content) == ["test_3", "test_2", "test_1"]
90+
91+
7592
def test_non_contiguous_positive(item_names_for):
7693
tests_content = """
7794
import pytest
@@ -460,6 +477,24 @@ def test_3():
460477
assert item_names_for(test_content) == ["test_3", "test_2", "test_1"]
461478

462479

480+
def test_combined_markers(item_names_for):
481+
test_content = """
482+
import pytest
483+
484+
@pytest.mark.order(2)
485+
def test_1():
486+
pass
487+
488+
def test_2():
489+
pass
490+
491+
@pytest.mark.order(index=1, before="test_2")
492+
def test_3():
493+
pass
494+
"""
495+
assert item_names_for(test_content) == ["test_3", "test_1", "test_2"]
496+
497+
463498
def test_dependency_after_unknown_test(item_names_for, capsys):
464499
test_content = """
465500
import pytest

0 commit comments

Comments
 (0)