Merge pull request #3108 from cheezman34/features
Optimize reorder_items in fixtures.py
This commit is contained in:
commit
0e1be01b7a
1
AUTHORS
1
AUTHORS
|
@ -3,6 +3,7 @@ merlinux GmbH, Germany, office at merlinux eu
|
||||||
|
|
||||||
Contributors include::
|
Contributors include::
|
||||||
|
|
||||||
|
Aaron Coleman
|
||||||
Abdeali JK
|
Abdeali JK
|
||||||
Abhijeet Kasurde
|
Abhijeet Kasurde
|
||||||
Ahn Ki-Wook
|
Ahn Ki-Wook
|
||||||
|
|
|
@ -4,7 +4,7 @@ import functools
|
||||||
import inspect
|
import inspect
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict, deque, defaultdict
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
import py
|
import py
|
||||||
|
@ -163,62 +163,51 @@ def get_parametrized_fixture_keys(item, scopenum):
|
||||||
|
|
||||||
def reorder_items(items):
|
def reorder_items(items):
|
||||||
argkeys_cache = {}
|
argkeys_cache = {}
|
||||||
|
items_by_argkey = {}
|
||||||
for scopenum in range(0, scopenum_function):
|
for scopenum in range(0, scopenum_function):
|
||||||
argkeys_cache[scopenum] = d = {}
|
argkeys_cache[scopenum] = d = {}
|
||||||
|
items_by_argkey[scopenum] = item_d = defaultdict(list)
|
||||||
for item in items:
|
for item in items:
|
||||||
keys = OrderedDict.fromkeys(get_parametrized_fixture_keys(item, scopenum))
|
keys = OrderedDict.fromkeys(get_parametrized_fixture_keys(item, scopenum))
|
||||||
if keys:
|
if keys:
|
||||||
d[item] = keys
|
d[item] = keys
|
||||||
return reorder_items_atscope(items, set(), argkeys_cache, 0)
|
for key in keys:
|
||||||
|
item_d[key].append(item)
|
||||||
|
items = OrderedDict.fromkeys(items)
|
||||||
|
return list(reorder_items_atscope(items, set(), argkeys_cache, items_by_argkey, 0))
|
||||||
|
|
||||||
|
|
||||||
def reorder_items_atscope(items, ignore, argkeys_cache, scopenum):
|
def reorder_items_atscope(items, ignore, argkeys_cache, items_by_argkey, scopenum):
|
||||||
if scopenum >= scopenum_function or len(items) < 3:
|
if scopenum >= scopenum_function or len(items) < 3:
|
||||||
return items
|
return items
|
||||||
items_done = []
|
items_deque = deque(items)
|
||||||
while 1:
|
items_done = OrderedDict()
|
||||||
items_before, items_same, items_other, newignore = \
|
scoped_items_by_argkey = items_by_argkey[scopenum]
|
||||||
slice_items(items, ignore, argkeys_cache[scopenum])
|
scoped_argkeys_cache = argkeys_cache[scopenum]
|
||||||
items_before = reorder_items_atscope(
|
while items_deque:
|
||||||
items_before, ignore, argkeys_cache, scopenum + 1)
|
no_argkey_group = OrderedDict()
|
||||||
if items_same is None:
|
slicing_argkey = None
|
||||||
# nothing to reorder in this scope
|
while items_deque:
|
||||||
assert items_other is None
|
item = items_deque.popleft()
|
||||||
return items_done + items_before
|
if item in items_done or item in no_argkey_group:
|
||||||
items_done.extend(items_before)
|
continue
|
||||||
items = items_same + items_other
|
argkeys = OrderedDict.fromkeys(k for k in scoped_argkeys_cache.get(item, []) if k not in ignore)
|
||||||
ignore = newignore
|
if not argkeys:
|
||||||
|
no_argkey_group[item] = None
|
||||||
|
|
||||||
def slice_items(items, ignore, scoped_argkeys_cache):
|
|
||||||
# we pick the first item which uses a fixture instance in the
|
|
||||||
# requested scope and which we haven't seen yet. We slice the input
|
|
||||||
# items list into a list of items_nomatch, items_same and
|
|
||||||
# items_other
|
|
||||||
if scoped_argkeys_cache: # do we need to do work at all?
|
|
||||||
it = iter(items)
|
|
||||||
# first find a slicing key
|
|
||||||
for i, item in enumerate(it):
|
|
||||||
argkeys = scoped_argkeys_cache.get(item)
|
|
||||||
if argkeys is not None:
|
|
||||||
newargkeys = OrderedDict.fromkeys(k for k in argkeys if k not in ignore)
|
|
||||||
if newargkeys: # found a slicing key
|
|
||||||
slicing_argkey, _ = newargkeys.popitem()
|
|
||||||
items_before = items[:i]
|
|
||||||
items_same = [item]
|
|
||||||
items_other = []
|
|
||||||
# now slice the remainder of the list
|
|
||||||
for item in it:
|
|
||||||
argkeys = scoped_argkeys_cache.get(item)
|
|
||||||
if argkeys and slicing_argkey in argkeys and \
|
|
||||||
slicing_argkey not in ignore:
|
|
||||||
items_same.append(item)
|
|
||||||
else:
|
else:
|
||||||
items_other.append(item)
|
slicing_argkey, _ = argkeys.popitem()
|
||||||
newignore = ignore.copy()
|
# we don't have to remove relevant items from later in the deque because they'll just be ignored
|
||||||
newignore.add(slicing_argkey)
|
for i in reversed(scoped_items_by_argkey[slicing_argkey]):
|
||||||
return (items_before, items_same, items_other, newignore)
|
if i in items:
|
||||||
return items, None, None, None
|
items_deque.appendleft(i)
|
||||||
|
break
|
||||||
|
if no_argkey_group:
|
||||||
|
no_argkey_group = reorder_items_atscope(
|
||||||
|
no_argkey_group, set(), argkeys_cache, items_by_argkey, scopenum + 1)
|
||||||
|
for item in no_argkey_group:
|
||||||
|
items_done[item] = None
|
||||||
|
ignore.add(slicing_argkey)
|
||||||
|
return items_done
|
||||||
|
|
||||||
|
|
||||||
def fillfixtures(function):
|
def fillfixtures(function):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Improve performance when collecting tests using many fixtures.
|
Loading…
Reference in New Issue