Skip to content

Commit a614d7c

Browse files
committed
Allow markers relative to parametrized tests
- the parameter value has no more to be included - see #38
1 parent ed6f3a4 commit a614d7c

File tree

4 files changed

+76
-15
lines changed

4 files changed

+76
-15
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@
99
- changed notation of relative markers in other modules - instead of using
1010
the dot notation, the standard pytest nodeid is used,
1111
see [#24](https://github.com/pytest-dev/pytest-order/issues/24)
12+
- using parametrized test names that include the parameter is no longer
13+
supported, just use the name without the parameter instead
1214

1315
### New features
1416
- added support for the ``pytest-dependency`` option ``automark_dependency``
15-
17+
- added support for relative ordering of parametrized tests using the test
18+
name without the parameter value,
19+
see [#38](https://github.com/pytest-dev/pytest-order/issues/38)
20+
1621
## [Version 0.11.0](https://pypi.org/project/pytest-order/0.11.0/) (2021-04-11)
1722
Adds support for multiple relative markers for the same test.
1823

docs/source/usage.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,3 +350,24 @@ attributes by using a list or tuple of test names:
350350
351351
This will ensure that ``test_first`` is executed both after ``test_second``
352352
and after ``test_other`` which resides in the module ``other_module.py``.
353+
354+
Relationships with parameterized tests
355+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
356+
If you want to reference parametrized tests, you can just use the test name
357+
without the parameter part, for example:
358+
359+
.. code:: python
360+
361+
import pytest
362+
363+
@pytest.mark.order(after=["test_second"])
364+
def test_first():
365+
assert True
366+
367+
@pytest.parametrize(param, [1, 2, 3])
368+
def test_second(param):
369+
assert True
370+
371+
Note that using the fully qualified test name, which would include the
372+
parameter (in this case ``test_second[1]``, ``test_second[2]`` etc) is not
373+
supported.

pytest_order/sorter.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ def __init__(self, config: Config, items: List[Function]) -> None:
5959
self.node_id_last: Dict[str, List[str]] = {}
6060
for item in self.items:
6161
self.node_ids[item.node_id] = item
62-
_, _, last_part = item.node_id.rpartition("::")
62+
last_part = item.node_id.rpartition("::")[2]
63+
if "[" in last_part:
64+
last_part = last_part.rpartition("[")[0]
6365
# save last nodeid component to avoid to iterate over all
6466
# items for each label
6567
self.node_id_last.setdefault(last_part, []).append(
@@ -174,22 +176,30 @@ def handle_order_mark(self, item: Item) -> None:
174176
if order is not None:
175177
item.nr_rel_items = 0
176178

177-
def item_from_label(
179+
def items_from_label(
178180
self, label: str, item: Item, is_cls_mark: bool
179-
) -> Optional[Item]:
181+
) -> List[Item]:
182+
"""
183+
Return the list of matching items from the given label.
184+
The list contains one item for a single matching test, several items
185+
in the case of a matching parametrized test, or no item in case of
186+
an invalid label.
187+
"""
180188
item_id = item.node_id
181189
label_len = len(label)
182190
last_comp = label.split("/")[-1].split("::")[-1]
191+
items = []
183192
with suppress(KeyError):
184193
node_ids = self.node_id_last[last_comp]
185194
for node_id in node_ids:
186-
if node_id.endswith(label):
195+
if (node_id.endswith(label) or node_id.endswith("]") and
196+
node_id.rpartition("[")[0].endswith(label)):
187197
id_start = node_id[:-label_len]
188198
if is_cls_mark and id_start.count("::") == 2:
189199
continue
190200
if item_id.startswith(id_start):
191-
return self.node_ids[node_id]
192-
return None
201+
items.append(self.node_ids[node_id])
202+
return items
193203

194204
def items_from_class_label(self, label: str, item: Item) -> List[Item]:
195205
items = []
@@ -216,14 +226,16 @@ def is_mark_for_class() -> bool:
216226
return "::" not in marker_name and is_class_mark()
217227

218228
is_cls_mark = is_class_mark()
219-
item_for_label = self.item_from_label(marker_name, item, is_cls_mark)
220-
if item_for_label:
221-
rel_mark = RelativeMark(item_for_label, item, move_after=is_after)
222-
if is_after or not is_cls_mark:
223-
self.rel_marks.append(rel_mark)
224-
else:
225-
self.rel_marks.insert(0, rel_mark)
226-
item.inc_rel_marks()
229+
items_for_label = self.items_from_label(marker_name, item, is_cls_mark)
230+
if items_for_label:
231+
for item_for_label in items_for_label:
232+
rel_mark = RelativeMark(
233+
item_for_label, item, move_after=is_after)
234+
if is_after or not is_cls_mark:
235+
self.rel_marks.append(rel_mark)
236+
else:
237+
self.rel_marks.insert(0, rel_mark)
238+
item.inc_rel_marks()
227239
return True
228240
else:
229241
if is_mark_for_class():

tests/test_relative_ordering.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,3 +490,26 @@ def test_3():
490490
"test_dependency_loop.py::test_3"
491491
)
492492
assert warning in out
493+
494+
495+
def test_dependency_on_parametrized_test(item_names_for):
496+
test_content = (
497+
"""
498+
import pytest
499+
500+
@pytest.mark.order(after="test_2")
501+
def test_1():
502+
pass
503+
504+
@pytest.mark.parametrize("arg", [1, 2, 3, 4])
505+
def test_2(arg):
506+
pass
507+
508+
@pytest.mark.order(before="test_2")
509+
def test_3():
510+
pass
511+
"""
512+
)
513+
assert item_names_for(test_content) == [
514+
"test_3", "test_2[1]", "test_2[2]", "test_2[3]", "test_2[4]", "test_1"
515+
]

0 commit comments

Comments
 (0)