Skip to content

Commit

Permalink
Added support for sparse ordinal behavior
Browse files Browse the repository at this point in the history
- tests taken from existing PR ftobia#29
- gaps in start and end lists are filled with unordered items
  • Loading branch information
mrbean-bremen committed Aug 2, 2020
1 parent d2703f0 commit f156094
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 39 deletions.
53 changes: 33 additions & 20 deletions pytest_ordering/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ def pytest_configure(config):
)

config_line = (
'run: specify ordering information for when tests should run '
'in relation to one another. ' + provided_by_pytest_ordering
'run: specify ordering information for when tests should run '
'in relation to one another. ' + provided_by_pytest_ordering
)
config.addinivalue_line('markers', config_line)

Expand Down Expand Up @@ -68,7 +68,7 @@ def pytest_collection_modifyitems(session, config, items):
if before:
before_items.setdefault(before, []).append(item)
continue

after = mark.kwargs.get('after')
if after:
after_items.setdefault(after, []).append(item)
Expand All @@ -79,27 +79,39 @@ def pytest_collection_modifyitems(session, config, items):
grouped_items.setdefault(order, []).append(item)

sorted_items = []
unordered_items = [grouped_items.pop(None, [])]
unordered_items = grouped_items.pop(None, [])

start_list = sorted((i for i in grouped_items.items() if i[0] >= 0),
key=operator.itemgetter(0))
end_list = sorted((i for i in grouped_items.items() if i[0] < 0),
key=operator.itemgetter(0))

sorted_items.extend([i[1] for i in start_list])
index = 0
for i, item_list in start_list:
while i > index and unordered_items:
sorted_items.append(unordered_items.pop(0))
index += 1
sorted_items.extend(item_list)
index += len(item_list)

end_list = reversed(sorted((i for i in grouped_items.items() if i[0] < 0),
key=operator.itemgetter(0)))
index = -1
sorted_end_list = []
for i, item_list in end_list:
while i < index and unordered_items:
sorted_end_list.append(unordered_items.pop())
index -= 1
sorted_end_list.extend(reversed(item_list))
index -= len(item_list)

sorted_items.extend(unordered_items)
sorted_items.extend([i[1] for i in end_list])
sorted_items.extend(reversed(sorted_end_list))
items[:] = sorted_items

items[:] = [item for sublist in sorted_items for item in sublist]

def _get_item_index_by_name(item_name):
index = None
for i, item in enumerate(items):
if getattr(item, 'name') == item_name:
index = i
break
return index

return i

for before_item_relative, _before_items in before_items.items():
index = _get_item_index_by_name(before_item_relative)
if index is not None:
Expand All @@ -108,12 +120,12 @@ def _get_item_index_by_name(item_name):
else:
if len(_before_items) == 1:
message_schema = "%s, indicated at parameter before of" \
+ " %s, doesn't exist"
+ " %s, doesn't exist"
message = message_schema % (before_item_relative,
_before_items[0].name)
else:
message_schema = "%s, indicated at parameter before of" \
+ " %s, doesn't exist"
+ " %s, doesn't exist"
test_names = ""
for i, before_item in enumerate(_before_items):
test_names += before_item.name
Expand All @@ -124,20 +136,21 @@ def _get_item_index_by_name(item_name):
message = message_schema % (before_item_relative, test_names)
warnings.warn(message, SyntaxWarning)
items.extend(_before_items)

for after_item_relative, _after_items in after_items.items():
index = _get_item_index_by_name(after_item_relative)
if index is not None:
for after_item in _after_items:
items.insert(index+1, after_item)
items.insert(index + 1, after_item)
else:
if len(_after_items) == 1:
message_schema = "%s, indicated at parameter after of" \
+ " %s, doesn't exist"
+ " %s, doesn't exist"
message = message_schema % (after_item_relative,
_after_items[0].name)
else:
message_schema = "%s, indicated at parameter after of" \
+ " %s, doesn't exist"
+ " %s, doesn't exist"
test_names = ""
for i, after_item in enumerate(_after_items):
test_names += after_item.name
Expand Down
16 changes: 16 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import pytest


@pytest.fixture
def item_names_for(testdir):

def _item_names_for(tests_content):
# some strange code to extract sorted items
items = testdir.getitems(tests_content)
hook = testdir.config.hook
hook.pytest_collection_modifyitems(session=items[0].session,
config=testdir.config, items=items)
return [item.name for item in items]

return _item_names_for

29 changes: 10 additions & 19 deletions tests/test_ordering.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,11 @@
# -*- coding: utf-8 -*-
import re
import warnings

import pytest

pytest_plugins = ['pytester']


@pytest.fixture
def item_names_for(testdir):

def _item_names_for(tests_content):
# some strange code to extract sorted items
items = testdir.getitems(tests_content)
hook = testdir.config.hook
hook.pytest_collection_modifyitems(session=items[0].session,
config=testdir.config, items=items)
return [item.name for item in items]

return _item_names_for


def test_no_marks(item_names_for):
tests_content = """
def test_1(): pass
Expand Down Expand Up @@ -150,7 +135,9 @@ def test_6(): pass
def test_7(): pass
"""

assert item_names_for(tests_content) == ['test_7', 'test_3', 'test_1', 'test_2', 'test_5', 'test_4', 'test_6']
assert item_names_for(tests_content) == ['test_7', 'test_3', 'test_1',
'test_2', 'test_5', 'test_4',
'test_6']


def test_non_contiguous_inc_none(item_names_for):
Expand All @@ -175,7 +162,8 @@ def test_5(): pass
def test_6(): pass
"""

assert item_names_for(tests_content) == ['test_2', 'test_3', 'test_1', 'test_6', 'test_5', 'test_4']
assert item_names_for(tests_content) == ['test_2', 'test_3', 'test_6',
'test_1', 'test_5', 'test_4']


def test_first_mark_class(item_names_for):
Expand Down Expand Up @@ -239,7 +227,8 @@ def test_5(self): pass
"""

assert item_names_for(tests_content) == ['test_4', 'test_5', 'test_3', 'test_1', 'test_2']
assert item_names_for(tests_content) == ['test_4', 'test_5', 'test_3',
'test_1', 'test_2']


def test_order_mark_class(item_names_for):
Expand All @@ -266,7 +255,8 @@ def test_4(self): pass
def test_5(self): pass
"""

assert item_names_for(tests_content) == ['test_3', 'test_4', 'test_5', 'test_1', 'test_2']
assert item_names_for(tests_content) == ['test_3', 'test_4', 'test_5',
'test_1', 'test_2']


def test_relative_to_other_tests(item_names_for):
Expand All @@ -283,6 +273,7 @@ def test_1(): pass
"""
assert item_names_for(tests_content) == ['test_1', 'test_2', 'test_3']


def test_relative_to_other_invalid_tests(item_names_for):
tests_content = """
import pytest
Expand Down
87 changes: 87 additions & 0 deletions tests/test_ordinals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-


def test_first(item_names_for):
tests_content = """
import pytest
def test_1(): pass
@pytest.mark.first
def test_2(): pass
"""
assert item_names_for(tests_content) == ['test_2', 'test_1']


def test_second(item_names_for):
tests_content = """
import pytest
def test_1(): pass
def test_2(): pass
def test_3(): pass
def test_4(): pass
@pytest.mark.second
def test_5(): pass
"""
assert item_names_for(tests_content) == ['test_1', 'test_5', 'test_2', 'test_3', 'test_4']


def test_third(item_names_for):
tests_content = """
import pytest
def test_1(): pass
def test_2(): pass
def test_3(): pass
@pytest.mark.third
def test_4(): pass
def test_5(): pass
"""
assert item_names_for(tests_content) == ['test_1', 'test_2', 'test_4', 'test_3', 'test_5']


def test_second_to_last(item_names_for):
tests_content = """
import pytest
def test_1(): pass
@pytest.mark.second_to_last
def test_2(): pass
def test_3(): pass
def test_4(): pass
def test_5(): pass
"""
assert item_names_for(tests_content) == ['test_1', 'test_3', 'test_4', 'test_2', 'test_5']


def test_last(item_names_for):
tests_content = """
import pytest
@pytest.mark.last
def test_1(): pass
def test_2(): pass
"""
assert item_names_for(tests_content) == ['test_2', 'test_1']


def test_first_last(item_names_for):
tests_content = """
import pytest
@pytest.mark.last
def test_1(): pass
@pytest.mark.first
def test_2(): pass
def test_3(): pass
"""
assert item_names_for(tests_content) == ['test_2', 'test_3', 'test_1']

0 comments on commit f156094

Please sign in to comment.