def test_eq(self): p = (packages.PackageRestriction('one', values.AlwaysTrue), ) p2 = (packages.PackageRestriction('one', values.AlwaysFalse), ) v = values.AlwaysTrue v2 = values.AlwaysFalse self.assertEqual(packages.Conditional('use', v, p), packages.Conditional('use', v, p)) self.assertNotEqual(packages.Conditional('use', v2, p), packages.Conditional('use', v, p)) self.assertNotEqual(packages.Conditional('use', v, p), packages.Conditional('use', v, p2)) self.assertNotEqual(packages.Conditional('use1', v, p), packages.Conditional('use', v, p))
def parse(cls, dep_str, element_class, operators=None, element_func=None, transitive_use_atoms=False, allow_src_uri_file_renames=False): """ :param dep_str: string abiding by DepSet syntax :param operators: mapping of node -> callable for special operators in DepSet syntax :param element_func: if None, element_class is used for generating elements, else it's used to generate elements. Mainly useful for when you need to curry a few args for instance generation, since element_class _must_ be a class :param element_class: class of generated elements """ if not isinstance(element_class, type): # yes, this blocks non new style classes. touch cookies. raise ValueError("element_class must be a new style class") if element_func is None: element_func = element_class if cls.parse_depset is not None and not (allow_src_uri_file_renames): restrictions = None if operators is None: has_conditionals, restrictions = cls.parse_depset( dep_str, element_func, boolean.AndRestriction, boolean.OrRestriction) else: for x in operators: if x not in ("", "||"): break else: has_conditionals, restrictions = cls.parse_depset( dep_str, element_func, operators.get(""), operators.get("||")) if restrictions is not None: if not has_conditionals and transitive_use_atoms: has_conditionals = cls._has_transitive_use_atoms( restrictions) return cls(restrictions, element_class, has_conditionals) restrictions = [] if operators is None: operators = { "||": boolean.OrRestriction, "": boolean.AndRestriction } raw_conditionals = [] depsets = [restrictions] node_conds = False words = iter(dep_str.split()) # we specifically do it this way since expandable_chain has a bit of nasty # overhead to the tune of 33% slower if allow_src_uri_file_renames: words = expandable_chain(words) k = None try: for k in words: if ")" == k: # no elements == error. if closures don't map up, # indexerror would be chucked from trying to pop # the frame so that is addressed. if not depsets[-1] or not raw_conditionals: raise ParseError(dep_str) elif raw_conditionals[-1] in operators: if len(depsets[-1]) == 1: depsets[-2].append(depsets[-1][0]) elif raw_conditionals[-1] == '' and ( len(raw_conditionals) == 1 or ('' == raw_conditionals[-2])): # if the frame is an and and the parent is an and, collapse it in. depsets[-2].extend(depsets[-1]) else: depsets[-2].append( operators[raw_conditionals[-1]](*depsets[-1])) else: node_conds = True c = raw_conditionals[-1] if c[0] == "!": c = values.ContainmentMatch(c[1:-1], negate=True) else: c = values.ContainmentMatch(c[:-1]) depsets[-2].append( packages.Conditional("use", c, tuple(depsets[-1]))) raw_conditionals.pop() depsets.pop() elif "(" == k: k = '' # push another frame on depsets.append([]) raw_conditionals.append(k) elif k[-1] == '?' or k in operators: # use conditional or custom op. # no tokens left == bad dep_str. k2 = words.next() if k2 != "(": raise ParseError(dep_str, k2) # push another frame on depsets.append([]) raw_conditionals.append(k) elif "|" in k: raise ParseError(dep_str, k) elif allow_src_uri_file_renames: try: k2 = words.next() except StopIteration: depsets[-1].append(element_func(k)) else: if k2 != '->': depsets[-1].append(element_func(k)) words.appendleft((k2, )) else: k3 = words.next() # file ename. depsets[-1].append(element_func(k, k3)) else: # node/element. depsets[-1].append(element_func(k)) except IGNORED_EXCEPTIONS: raise except IndexError: # [][-1] for a frame access, which means it was a parse error. raise except StopIteration: if k is None: raise raise ParseError(dep_str, k) except Exception as e: raise_from(ParseError(dep_str, e)) # check if any closures required if len(depsets) != 1: raise ParseError(dep_str) if transitive_use_atoms and not node_conds: # localize to this scope for speed. element_class = transitive_use_atom # we can't rely on iter(self) here since it doesn't # descend through boolean restricts. node_conds = cls._has_transitive_use_atoms(restrictions) return cls(tuple(restrictions), element_class, node_conds)