1# Stateless utilities 2# 3# This entire module is exported into the config.* namespace (see 4# __init__.py), so be careful to avoid namespace conflicts. Do not 5# import config.util directly. Instead, import config and access only 6# the exported objects. 7 8def classify(items, functional, args=(), kwargs=dict()): 9 '''Classify items as True or False using boolean functional on sets. 10 11 An item can only be identified as False if functional([item]) is 12 false, but an item is True if functional(List) is True and item in 13 List. 14 15 Functional may return True (all items are True), False (at least one 16 item is False) or a list of suggestions for items that may have been 17 False (implies that at least one item is False). The list of 18 suggestions does not have to be accurate, but classification will be 19 faster if it is accurate. 20 ''' 21 items = list(items) # In case a set or other iterable was passed in 22 23 result = functional(items, *args, **kwargs) 24 if result is True: 25 return items, [] # All succeeded 26 if len(items) == 1: 27 return [], items # Sole failure 28 if result is False: 29 suggested = [] 30 else: 31 suggested = list(result) 32 items = [i for i in items if i not in suggested] 33 good = [] 34 bad = [] 35 if len(items) < 5: # linear check 36 groups = [[i] for i in items] 37 else: # bisect 38 groups = [items[:len(items)//2], items[len(items)//2:]] 39 groups += [[i] for i in suggested] 40 for grp in groups: 41 g, b = classify(grp, functional, args, kwargs) 42 good += g 43 bad += b 44 return good, bad 45 46class NamedInStderr: 47 '''Hepler class to log the (string) items that are written to stderr on failure. 48 49 In the common case, all the missing items are named in the linker 50 error and the rest can be confirmed True in a single batch. 51 ''' 52 def __init__(self, items): 53 self.named = [] 54 self.items = items 55 56 def examineStderr(self, ret, out, err): 57 if ret: 58 self.named += [i for i in self.items if i in err] 59 60class memoize(dict): 61 '''Memoizing decorator. No support for keyword arguments.''' 62 def __init__(self, func): 63 self.func = func 64 65 def __call__(self, *args): 66 try: 67 return self[args] 68 except KeyError: 69 ret = self[args] = self.func(*args) 70 return ret 71