@@ -44,7 +44,7 @@ def pytest_configure(config):
44
44
)
45
45
config .addinivalue_line ("markers" , config_line )
46
46
47
- if config .getoption ("indulgent-ordering " ):
47
+ if config .getoption ("indulgent_ordering " ):
48
48
# We need to dynamically add this `tryfirst` decorator to the plugin:
49
49
# only when the CLI option is present should the decorator be added.
50
50
# Thus, we manually run the decorator on the class function and
@@ -65,14 +65,18 @@ def pytest_addoption(parser):
65
65
"""Set up CLI option for pytest"""
66
66
group = parser .getgroup ("ordering" )
67
67
group .addoption ("--indulgent-ordering" , action = "store_true" ,
68
- dest = "indulgent-ordering " ,
68
+ dest = "indulgent_ordering " ,
69
69
help = "Request that the sort order provided by "
70
70
"pytest-order be applied before other sorting, "
71
71
"allowing the other sorting to have priority" )
72
72
group .addoption ("--order-scope" , action = "store" ,
73
- dest = "order-scope " ,
73
+ dest = "order_scope " ,
74
74
help = "Defines the scope used for ordering. Possible values"
75
75
"are 'session' (default), 'module', and 'class'" )
76
+ group .addoption ("--sparse-ordering" , action = "store_true" ,
77
+ dest = "sparse_ordering" ,
78
+ help = "If there are gaps between ordinals they are filled "
79
+ "with unordered tests." )
76
80
77
81
78
82
class OrderingPlugin (object ):
@@ -126,14 +130,6 @@ def mark_binning(item, keys, start, end, before, after, unordered):
126
130
return False
127
131
128
132
129
- def insert (items , sort ):
130
- if isinstance (items , tuple ):
131
- list_items = items [1 ]
132
- else :
133
- list_items = items
134
- sort += list_items
135
-
136
-
137
133
def insert_before (name , items , sort ):
138
134
regex_name = re .escape (name ) + r"(:?\.\w+)?$"
139
135
for pos , item in enumerate (sort ):
@@ -160,7 +156,7 @@ def insert_after(name, items, sort):
160
156
return False
161
157
162
158
163
- def do_modify_items (items ):
159
+ def do_modify_items (items , sparse_ordering ):
164
160
before_item = {}
165
161
after_item = {}
166
162
start_item = {}
@@ -174,13 +170,8 @@ def do_modify_items(items):
174
170
start_item = sorted (start_item .items ())
175
171
end_item = sorted (end_item .items ())
176
172
177
- sorted_list = []
178
-
179
- for entries in start_item :
180
- insert (entries , sorted_list )
181
- insert (unordered_list , sorted_list )
182
- for entries in end_item :
183
- insert (entries , sorted_list )
173
+ sorted_list = sort_numbered_items (start_item , end_item , unordered_list ,
174
+ sparse_ordering )
184
175
185
176
still_left = 0
186
177
length = len (before_item ) + len (after_item )
@@ -216,24 +207,51 @@ def do_modify_items(items):
216
207
return sorted_list
217
208
218
209
210
+ def sort_numbered_items (start_item , end_item , unordered_list , sparse_ordering ):
211
+ sorted_list = []
212
+ index = 0
213
+ for entries in start_item :
214
+ if sparse_ordering :
215
+ while entries [0 ] > index and unordered_list :
216
+ sorted_list .append (unordered_list .pop (0 ))
217
+ index += 1
218
+ sorted_list += entries [1 ]
219
+ index += len (entries [1 ])
220
+ mid_index = len (sorted_list )
221
+ index = - 1
222
+ for entries in reversed (end_item ):
223
+ if sparse_ordering :
224
+ while entries [0 ] < index and unordered_list :
225
+ sorted_list .insert (mid_index , unordered_list .pop ())
226
+ index -= 1
227
+ for item in reversed (entries [1 ]):
228
+ sorted_list .insert (mid_index , item )
229
+ index += len (entries [1 ])
230
+ for unordered_item in reversed (unordered_list ):
231
+ sorted_list .insert (mid_index , unordered_item )
232
+ return sorted_list
233
+
234
+
219
235
def modify_items (session , config , items ):
220
- scope = config .getoption ("order-scope" )
236
+ sparse_ordering = config .getoption ("sparse_ordering" )
237
+ scope = config .getoption ("order_scope" )
221
238
if scope not in ("session" , "module" , "class" ):
222
239
if scope is not None :
223
240
warn ("Unknown order scope '{}', ignoring it. "
224
241
"Valid scopes are 'session', 'module' and 'class'."
225
242
.format (scope ))
226
243
scope = "session"
227
244
if scope == "session" :
228
- sorted_list = do_modify_items (items )
245
+ sorted_list = do_modify_items (items , sparse_ordering )
229
246
elif scope == "module" :
230
247
module_items = OrderedDict ()
231
248
for item in items :
232
249
module_path = item .nodeid [:item .nodeid .index ("::" )]
233
250
module_items .setdefault (module_path , []).append (item )
234
251
sorted_list = []
235
252
for module_item_list in module_items .values ():
236
- sorted_list .extend (do_modify_items (module_item_list ))
253
+ sorted_list .extend (do_modify_items (
254
+ module_item_list , sparse_ordering ))
237
255
else : # class scope
238
256
class_items = OrderedDict ()
239
257
for item in items :
@@ -244,6 +262,7 @@ def modify_items(session, config, items):
244
262
class_items .setdefault (class_path , []).append (item )
245
263
sorted_list = []
246
264
for class_item_list in class_items .values ():
247
- sorted_list .extend (do_modify_items (class_item_list ))
265
+ sorted_list .extend (do_modify_items (
266
+ class_item_list , sparse_ordering ))
248
267
249
268
items [:] = sorted_list
0 commit comments