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

Implementation of markers #37

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ Sergei Chipiga <[email protected]>
Ben Greene <[email protected]>
Adam Talsma <[email protected]>
Brian Maissy <[email protected]>
Jonas Zinn <[email protected]>
5 changes: 5 additions & 0 deletions example/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def test_foo():
assert True

def test_bar():
assert True
17 changes: 17 additions & 0 deletions example/test_number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import pytest

@pytest.mark.run(order=-2)
def test_three():
assert True

@pytest.mark.run(order=-1)
def test_four():
assert True

@pytest.mark.run(order=2)
def test_two():
assert True

@pytest.mark.run(order=1)
def test_one():
assert True
17 changes: 17 additions & 0 deletions example/test_ordinals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import pytest

@pytest.mark.run('second_to_last')
def test_three():
assert True

@pytest.mark.run('last')
def test_four():
assert True

@pytest.mark.run('second')
def test_two():
assert True

@pytest.mark.run('first')
def test_one():
assert True
17 changes: 17 additions & 0 deletions example/test_other.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import pytest

@pytest.mark.second_to_last
def test_three():
assert True

@pytest.mark.last
def test_four():
assert True

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

@pytest.mark.first
def test_one():
assert True
9 changes: 9 additions & 0 deletions example/test_quickstart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import pytest

@pytest.mark.order2
def test_foo():
assert True

@pytest.mark.order1
def test_bar():
assert True
12 changes: 12 additions & 0 deletions example/test_relative.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import pytest

@pytest.mark.run(after='test_second')
def test_third():
assert True

def test_second():
assert True

@pytest.mark.run(before='test_second')
def test_first():
assert True
173 changes: 144 additions & 29 deletions pytest_ordering/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@
from ._version import __version__

import operator

import re
import pytest
try:
from collections import OrderedDict
except:
from ordereddict import OrderedDict
import os
import sys

orders_map = {
'first': 0,
Expand All @@ -21,7 +27,7 @@
'fifth_to_last': -5,
'sixth_to_last': -6,
'seventh_to_last': -7,
'eighth_to_last': -8,
'eighth_to_last': -8
}


Expand All @@ -46,37 +52,146 @@ def pytest_configure(config):
config.addinivalue_line('markers', config_line)


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

for item in items:

for mark_name, order in orders_map.items():
mark = item.get_closest_marker(mark_name)
def get_filename(item):
name = item.location[0]
if os.sep in name:
name = item.location[0].rsplit(os.sep, 1)[1]
return name[:-3]

if mark:
item.add_marker(pytest.mark.run(order=order))
break

def mark_binning(item, keys, start, end, before, after, unordered):
match_order = re.compile(r"order(\d+)(:?,|$)")
find_order = match_order.search(",".join(keys))
if find_order:
order = int(find_order.group(1))
start.setdefault(order, []).append(item)
return True
elif "run" in keys:
mark = item.get_closest_marker('run')

if mark:
order = mark.kwargs.get('order')
order = mark.kwargs.get('order')
before_mark = mark.kwargs.get('before')
after_mark = mark.kwargs.get('after')
if order is not None:
order = int(order)
if order < 0:
end.setdefault(order, []).append(item)
else:
start.setdefault(order, []).append(item)
elif before_mark:
if "." not in before_mark:
prefix = get_filename(item)
before_mark = prefix + "." + before_mark
before.setdefault(before_mark, []).append(item)
elif after_mark:
if "." not in after_mark:
prefix = get_filename(item)
after_mark = prefix + "." + after_mark

after.setdefault(after_mark, []).append(item)
else:
order = None

grouped_items.setdefault(order, []).append(item)

sorted_items = []
unordered_items = [grouped_items.pop(None, [])]
for ordinal, position in orders_map.items():
if ordinal in mark.args:
if position < 0:
end.setdefault(position, []).append(item)
else:
start.setdefault(position, []).append(item)
break
return True
for mark_name, order in orders_map.items():
mark = item.get_closest_marker(mark_name)
if mark:
order = int(order)
if order < 0:
end.setdefault(order, []).append(item)
else:
start.setdefault(order, []).append(item)
return True
unordered.append(item)
return False

def insert(items, sort):
list_items = []
if isinstance(items, tuple):
list_items = items[1]
else:
list_items = items
sort += list_items

def insert_before( name, items, sort):
regex_name = re.escape(name) + r"(:?\.\w+)?$"
for pos, item in enumerate(sort):
prefix = get_filename(item)
item_name = prefix + "." + item.location[2]
if re.match(regex_name, item_name):
if pos == 0:
sort[:] = items + sort
else:
sort[pos:1] = items
return True
return False

def insert_after(name, items, sort):
regex_name = re.escape(name) + r"(:?\.\w+)?$"
for pos, item in reversed(list(enumerate(sort))):
prefix = get_filename(item)
item_name = prefix + "." + item.location[2]
if re.match(regex_name, item_name):
sort[pos+1:1] = items
return True

return False

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))
def pytest_collection_modifyitems(session, config, items):
before_item = {}
after_item = {}
start_item = {}
end_item = {}
unordered_list = []

sorted_items.extend([i[1] for i in start_list])
sorted_items.extend(unordered_items)
sorted_items.extend([i[1] for i in end_list])
for item in items:
mark_binning(item, item.keywords.keys(), start_item, end_item, before_item, after_item, unordered_list)

start_item = sorted(start_item.items())
end_item = sorted(end_item.items())

sorted_list = []

for entries in start_item:
insert(entries, sorted_list)
insert(unordered_list, sorted_list)
for entries in end_item:
insert(entries, sorted_list)

still_left = 0
length = len(before_item) + len(after_item)

while( still_left != length):
still_left = length
remove_labels = []
for label, before in before_item.items():
if insert_before(label, before, sorted_list):
remove_labels.append(label)
for label in remove_labels:
del before_item[label]

remove_labels = []
for label, after in after_item.items():
if insert_after(label, after, sorted_list):
remove_labels.append(label)
for label in remove_labels:
del after_item[label]

length = len(before_item) + len(after_item)
if length:
sys.stdout.write("WARNING: can not execute test relative to others: ")
for label, entry in before_item.items():
sys.stdout.write( label + " ")
sorted_list += entry
for label, entry in after_item.items():
sys.stdout.write( label + " ")
sorted_list += entry
sys.stdout.flush()
print("enqueue them behind the others")

items[:] = sorted_list

items[:] = [item for sublist in sorted_items for item in sublist]
2 changes: 1 addition & 1 deletion pytest_ordering/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.6'
__version__ = '1.0'
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: PyPy',
],
)
Loading