Index: recipe_engine/post_process.py |
diff --git a/recipe_engine/post_process.py b/recipe_engine/post_process.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..47fb6a5f54853d0e2c201fa1f52fce44a2605da6 |
--- /dev/null |
+++ b/recipe_engine/post_process.py |
@@ -0,0 +1,95 @@ |
+# Copyright 2016 The LUCI Authors. All rights reserved. |
+# Use of this source code is governed under the Apache License, Version 2.0 |
+# that can be found in the LICENSE file. |
martiniss
2016/10/03 19:14:19
Add a file doc string and tests?
|
+ |
+import re |
+ |
+from collections import defaultdict, OrderedDict |
+ |
+ |
+class _filterObject(object): |
+ def __init__(self, data, re_data): |
+ self.data = data |
+ self.re_data = re_data |
+ |
+ def __call__(self, check, step_odict): |
+ includes = self.data.copy() |
+ re_data = self.re_data.copy() |
+ |
+ re_usage_count = defaultdict(int) |
+ |
+ to_ret = OrderedDict() |
+ for name, step in step_odict.iteritems(): |
+ field_set = includes.pop(name, None) |
+ if not field_set: |
dnj
2016/10/04 16:42:33
Can we have an error if both specific and regex ma
dnj
2016/10/04 16:42:34
nit: You're using "is None" below, but "not" here.
iannucci
2016/10/06 20:28:08
I don't think that's an error case, I've documente
iannucci
2016/10/06 20:28:09
Done.
|
+ for exp, (_, _, fset) in re_data.iteritems(): |
+ if exp.match(name): |
+ re_usage_count[exp] += 1 |
+ field_set = fset |
+ break |
+ if field_set is None: |
+ continue |
+ if len(field_set) == 0: |
+ to_ret[name] = step |
+ else: |
+ to_ret[name] = { |
+ k: v for k, v in step.iteritems() |
+ if k in field_set or k == 'name' |
+ } |
+ |
+ check('all includes were used', len(includes) == 0) |
+ |
+ for regex, (at_least, at_most, _) in re_data.iteritems(): |
+ check(re_usage_count[regex] >= at_least) |
+ if at_most is not None: |
+ check(re_usage_count[regex] < at_most) |
dnj
2016/10/04 16:42:34
If I say, "at most 3", I would expect 3 to be vali
iannucci
2016/10/06 20:28:09
Done.
|
+ |
+ return to_ret |
+ |
+ def include(self, step_name, *fields): |
+ new_data = self.data.copy() |
+ new_data[step_name] = set(fields) |
+ return _filterObject(new_data, self.re_data) |
+ |
+ def include_re(self, step_name_re, at_least=1, at_most=None, *fields): |
+ new_re_data = self.re_data.copy() |
+ new_re_data[re.compile(step_name_re)] = (at_least, at_most, set(fields)) |
dnj
2016/10/04 16:42:34
Let's use a namedtuple here. Simple to create one
iannucci
2016/10/06 20:28:08
Done.
|
+ return _filterObject(self.data, new_re_data) |
+ |
+ |
+def NewFilter(*steps): |
dnj
2016/10/04 16:42:34
docstrings!
iannucci
2016/10/06 20:28:09
Done.
|
+ return _filterObject({name: set() for name in steps}, {}) |
+ |
+ |
+def DoesntRun(check, step_odict, *steps): |
dnj
2016/10/04 16:42:34
This looks awkward. How about DoesNotRun?
iannucci
2016/10/06 20:28:09
Done.
|
+ banSet = set(steps) |
+ for step_name in step_odict: |
+ check(step_name not in banSet) |
+ |
+ |
+def DoesntRunRE(check, step_odict, *step_regexes): |
dnj
2016/10/04 16:42:34
(same)
iannucci
2016/10/06 20:28:09
Done.
|
+ step_regexes = [re.compile(r) for r in step_regexes] |
dnj
2016/10/04 16:42:34
Assert that "step_odict" is an OrderedDict? Here a
iannucci
2016/10/06 20:28:09
That would be a terrible abstraction violation :D.
|
+ for step_name in step_odict: |
+ for r in step_regexes: |
+ check(not r.match(step_name)) |
+ |
+ |
+def MustRun(check, step_odict, *steps): |
+ step_names = step_odict.keys() |
+ for step_name in steps: |
+ check(step_name in step_names) |
+ |
+ |
+def MustRunRE(check, step_odict, step_regex, at_least=1, at_most=None): |
martiniss
2016/10/03 19:14:18
Maybe have examples of these in other engine tests
iannucci
2016/10/06 20:28:09
there are docs now, I don't think an example of ev
|
+ step_regex = re.compile(step_regex) |
dnj
2016/10/04 16:42:34
WDYT about allowing "step_regex" to actually be a
iannucci
2016/10/06 20:28:08
It's already the case.
f = re.compile('foo')
F
|
+ matches = 0 |
+ for step_name in step_odict: |
+ if step_regex.match(step_name): |
+ matches += 1 |
+ check(matches >= at_least) |
+ if at_most is not None: |
+ check(matches < at_most) |
+ |
+ |
+def DropExpectation(_check, _step_odict): |
+ return [] |