def test_consistency(self): from random import randint from xoutil.eight import range from xoutil.collections import BitPascalSet count = 5 for test in range(count): size = randint(20, 60) ranges = (range(i, randint(i, i + 3)) for i in range(1, size)) s1 = BitPascalSet(*ranges) ranges = (range(i, randint(i, i + 3)) for i in range(1, size)) s2 = BitPascalSet(*ranges) ss1 = set(s1) ss2 = set(s2) self.assertEqual(s1, ss1) self.assertEqual(s1 - s2, ss1 - ss2) self.assertEqual(s2 - s1, ss2 - ss1) self.assertEqual(s1 & s2, ss1 & ss2) self.assertEqual(s2 & s1, ss2 & ss1) self.assertEqual(s1 | s2, ss1 | ss2) self.assertEqual(s2 | s1, ss2 | ss1) self.assertEqual(s1 ^ s2, ss1 ^ ss2) self.assertEqual(s2 ^ s1, ss2 ^ ss1) self.assertLess(s1 - s2, s1) self.assertLess(s1 - s2, ss1) self.assertLessEqual(s1 - s2, s1) self.assertLessEqual(s1 - s2, ss1) self.assertGreater(s1, s1 - s2) self.assertGreater(s1, ss1 - ss2) self.assertGreaterEqual(s1, s1 - s2) self.assertGreaterEqual(s1, ss1 - ss2)
def addRule(self, doc, func, _preprocess=1): doc = self.strip_comments(doc) fn = func rules = doc.split() # First, detect all lines where a new production is given. index = [] for i in range(len(rules)): if rules[i] == '::=': index.append(i-1) index.append(len(rules)) # Now process each rule add it the rules. We take care of making of # splitting right hand sides with vertical bars into several rules. for i in range(len(index)-1): lhs = rules[index[i]] rhss = rules[index[i]+2:index[i+1]] lhs_rules = self.rules.setdefault(lhs, []) for rhs in iter_rhss(rhss): rule = (lhs, tuple(rhs)) if _preprocess: rule, fn = self.preprocess(rule, func) lhs_rules.append(rule) self.rule2func[rule] = fn self.rule2name[rule] = func.__name__[2:] self.ruleschanged = 1
def buildTree(self, nt, item, tokens, k): state, parent = item choices = [] for rule in self.states[state].complete: if rule[0] == nt: choices.append(rule) rule = choices[0] if len(choices) > 1: rule = self.ambiguity(choices) rhs = rule[1] attr = [None] * len(rhs) for i in range(len(rhs)-1, -1, -1): sym = rhs[i] if sym not in self.newrules: if sym != self._BOF: attr[i] = tokens[k-1] key = (item, k) item, k = self.predecessor(key, None) elif self._NULLABLE == sym[0:len(self._NULLABLE)]: attr[i] = self.deriveEpsilon(sym) else: key = (item, k) why = self.causal(key) attr[i] = self.buildTree(sym, why[0], tokens, why[1]) item, k = self.predecessor(key, why) return self.rule2func[self.new2old[rule]](attr)
def parse(self, tokens): sets = [[(1, 0), (2, 0)]] self.links = {} if self.ruleschanged: self.computeNull() self.newrules = {} self.new2old = {} self.makeNewRules() self.ruleschanged = 0 self.edges, self.cores = {}, {} self.states = {0: self.makeState0()} self.makeState(0, self._BOF) for i in range(len(tokens)): sets.append([]) if sets[i] == []: break self.makeSet(tokens[i], sets, i) else: sets.append([]) self.makeSet(None, sets, len(tokens)) finalitem = (self.finalState(tokens), 0) if finalitem not in sets[-2]: if len(tokens) > 0: self.error(tokens[i-1]) else: self.error(None) return self.buildTree(self._START, finalitem, tokens, len(sets)-2)
def test_operators(self): from xoutil.eight import range from xoutil.collections import BitPascalSet g = lambda s: (i for i in s) s1 = BitPascalSet[1:4, 9, 15:18] r1 = range(1, 18) s2 = BitPascalSet(s1, 20) self.assertTrue(s1.issubset(s1)) self.assertTrue(s1.issubset(set(s1))) self.assertTrue(s1.issubset(list(s1))) self.assertTrue(s1.issubset(g(s1))) self.assertTrue(s1.issubset(r1)) self.assertTrue(s1.issubset(set(r1))) self.assertTrue(s1.issubset(list(r1))) self.assertTrue(s1.issubset(g(r1))) self.assertTrue(s2.issuperset(s2)) self.assertTrue(s2.issuperset(s1)) self.assertTrue(s2.issuperset(set(s1))) self.assertTrue(s2.issuperset(list(s1))) self.assertTrue(s2.issuperset(g(s1))) self.assertTrue(s1 <= set(s1)) self.assertTrue(s1 < s2) self.assertTrue(s1 <= s2) self.assertTrue(s1 < set(s2)) self.assertTrue(s1 <= set(s2)) self.assertTrue(s1 < set(r1)) self.assertTrue(s1 <= set(r1)) self.assertTrue(s2 >= s2) self.assertTrue(s2 >= set(s2)) self.assertTrue(s2 > s1) self.assertTrue(s2 > set(s1)) self.assertTrue(s2 >= s1) self.assertTrue(s2 >= set(s1))
def test_syntax_sugar(self): from xoutil.eight import range from xoutil.collections import BitPascalSet s1 = BitPascalSet[1:4, 9, 15:18] s2 = BitPascalSet[3:18] self.assertEqual(str(s1), '{1..3, 9, 15..17}') self.assertEqual(str(s1 ^ s2), '{1, 2, 4..8, 10..14}') self.assertEqual(list(BitPascalSet[3:18]), list(range(3, 18)))
def test_iscollection(): from xoutil.eight import range from xoutil.types import is_collection from xoutil.collections import UserList, UserDict assert is_collection('all strings are iterable') is False assert is_collection(1) is False assert is_collection(range(1)) is True assert is_collection({}) is False assert is_collection(tuple()) is True assert is_collection(set()) is True assert is_collection(a for a in range(100)) is True class Foobar(UserList): pass assert is_collection(Foobar()) is True class Foobar(UserDict): pass assert is_collection(Foobar()) is False
def test_pickle(self): ns = types.SimpleNamespace(breakfast="spam", lunch="spam") for protocol in range(pickle.HIGHEST_PROTOCOL + 1): pname = "protocol {}".format(protocol) try: ns_pickled = pickle.dumps(ns, protocol) except TypeError: raise TypeError(pname) ns_roundtrip = pickle.loads(ns_pickled) self.assertEqual(ns, ns_roundtrip, pname)
def deriveEpsilon(self, nt): if len(self.newrules[nt]) > 1: rule = self.ambiguity(self.newrules[nt]) else: rule = self.newrules[nt][0] rhs = rule[1] attr = [None] * len(rhs) for i in range(len(rhs)-1, -1, -1): attr[i] = self.deriveEpsilon(rhs[i]) return self.rule2func[self.new2old[rule]](attr)
def test_multiset_operations(self): # Verify that adding a zero counter will strip zeros and negatives c = Counter(a=10, b=-2, c=0) + Counter() self.assertEqual(dict(c), dict(a=10)) elements = 'abcd' for i in range(1000): # test random pairs of multisets p = Counter(dict((elem, randrange(-2, 4)) for elem in elements)) p.update(e=1, f=-1, g=0) q = Counter(dict((elem, randrange(-2, 4)) for elem in elements)) q.update(h=1, i=-1, j=0) for counterop, numberop in [ (Counter.__add__, lambda x, y: max(0, x+y)), (Counter.__sub__, lambda x, y: max(0, x-y)), (Counter.__or__, lambda x, y: max(0, x, y)), (Counter.__and__, lambda x, y: max(0, min(x, y))), ]: result = counterop(p, q) for x in elements: self.assertEqual(numberop(p[x], q[x]), result[x], (counterop, x, p, q)) # verify that results exclude non-positive counts self.assertTrue(x > 0 for x in result.values()) elements = 'abcdef' for i in range(100): # verify that random multisets with no repeats are exactly like # sets p = Counter(dict((elem, randrange(0, 2)) for elem in elements)) q = Counter(dict((elem, randrange(0, 2)) for elem in elements)) for counterop, setop in [ (Counter.__sub__, set.__sub__), (Counter.__or__, set.__or__), (Counter.__and__, set.__and__), ]: counter_result = counterop(p, q) set_result = setop(set(p.elements()), set(q.elements())) self.assertEqual(counter_result, dict.fromkeys(set_result, 1))
def _normalize_positions(self): '''Update the `positions` dictionaries.''' from xoutil.eight import range, iteritems aux = {} for par, ps in iteritems(self.scheme): for pos in ps['pos']: l = aux.setdefault(pos, []) l.append(par) res, pivot = {}, 0 for pos in range(min(aux), max(aux) + 1): if pos in aux: res[pivot] = sorted(aux[pos]) pivot += 1 self.positions = res
def ambiguity(self, rules): # # XXX - problem here and in collectRules() if the same rule # appears in >1 method. Also undefined results if rules # causing the ambiguity appear in the same method. # sortlist = [] name2index = {} for i in range(len(rules)): lhs, rhs = rule = rules[i] name = self.rule2name[self.new2old[rule]] sortlist.append((len(rhs), name)) name2index[name] = i sortlist.sort() list = [a_b[1] for a_b in sortlist] return rules[name2index[self.resolve(list)]]
def test_inplace_operations(self): elements = 'abcd' for i in range(1000): # test random pairs of multisets p = Counter(dict((elem, randrange(-2, 4)) for elem in elements)) p.update(e=1, f=-1, g=0) q = Counter(dict((elem, randrange(-2, 4)) for elem in elements)) q.update(h=1, i=-1, j=0) for inplace_op, regular_op in [ (Counter.__iadd__, Counter.__add__), (Counter.__isub__, Counter.__sub__), (Counter.__ior__, Counter.__or__), (Counter.__iand__, Counter.__and__), ]: c = p.copy() c_id = id(c) regular_result = regular_op(c, q) inplace_result = inplace_op(c, q) self.assertEqual(inplace_result, regular_result) self.assertEqual(id(inplace_result), c_id)
def test_basics(self): c = Counter('abcaba') self.assertEqual(c, Counter({'a': 3, 'b': 2, 'c': 1})) self.assertEqual(c, Counter(a=3, b=2, c=1)) self.assert_(isinstance(c, dict)) self.assert_(isinstance(c, Mapping)) self.assertTrue(issubclass(Counter, dict)) self.assertTrue(issubclass(Counter, Mapping)) self.assertEqual(len(c), 3) self.assertEqual(sum(c.values()), 6) self.assertEqual(sorted(c.values()), [1, 2, 3]) self.assertEqual(sorted(c.keys()), ['a', 'b', 'c']) self.assertEqual(sorted(c), ['a', 'b', 'c']) self.assertEqual(sorted(c.items()), [('a', 3), ('b', 2), ('c', 1)]) self.assertEqual(c['b'], 2) self.assertEqual(c['z'], 0) self.assertEqual(c.__contains__('c'), True) self.assertEqual(c.__contains__('z'), False) self.assertEqual(c.get('b', 10), 2) self.assertEqual(c.get('z', 10), 10) self.assertEqual(c, dict(a=3, b=2, c=1)) if not PY3: self.assertEqual(repr(c), "Counter({u'a': 3, u'b': 2, u'c': 1})") else: self.assertEqual(repr(c), "Counter({'a': 3, 'b': 2, 'c': 1})") self.assertEqual(c.most_common(), [('a', 3), ('b', 2), ('c', 1)]) for i in range(5): self.assertEqual(c.most_common(i), [('a', 3), ('b', 2), ('c', 1)][:i]) self.assertEqual(''.join(sorted(c.elements())), 'aaabbc') c['a'] += 1 # increment an existing value c['b'] -= 2 # sub existing value to zero del c['c'] # remove an entry del c['c'] # make sure that del doesn't raise KeyError c['d'] -= 2 # sub from a missing value c['e'] = -5 # directly assign a missing value c['f'] += 4 # add to a missing value self.assertEqual(c, dict(a=4, b=0, d=-2, e=-5, f=4)) self.assertEqual(''.join(sorted(c.elements())), 'aaaaffff') self.assertEqual(c.pop('f'), 4) self.assertNotIn('f', c) for i in range(3): elem, cnt = c.popitem() self.assertNotIn(elem, c) c.clear() self.assertEqual(c, {}) self.assertEqual(repr(c), 'Counter()') self.assertRaises(NotImplementedError, Counter.fromkeys, 'abc') self.assertRaises(TypeError, hash, c) c.update(dict(a=5, b=3)) c.update(c=1) c.update(Counter('a' * 50 + 'b' * 30)) c.update() # test case with no args c.__init__('a' * 500 + 'b' * 300) c.__init__('cdc') c.__init__() self.assertEqual(c, dict(a=555, b=333, c=3, d=1)) self.assertEqual(c.setdefault('d', 5), 1) self.assertEqual(c['d'], 1) self.assertEqual(c.setdefault('e', 5), 5) self.assertEqual(c['e'], 5)
def nameof(*args, **kwargs): '''Obtain the name of each one of a set of objects. .. versionadded:: 1.4.0 .. versionchanged:: 1.6.0 - Keyword arguments are now keyword-only arguments. - Support for several objects - Improved the semantics of parameter `full`. - Added the `safe` keyword argument. If no object is given, None is returned; if only one object is given, a single string is returned; otherwise a list of strings is returned. The name of an object is normally the variable name in the calling stack. If the object is not present calling frame, up to five frame levels are searched. Use the `depth` keyword argument to specify a different starting point and the search will proceed five levels from this frame up. If the same object has several good names a single one is arbitrarily chosen. Good names candidates are retrieved based on the keywords arguments `full`, `inner`, `safe` and `typed`. If `typed` is True and the object is not a type name or a callable (see `xoutil.inspect.type_name`:func:), then the `type` of the object is used instead. If `inner` is True we try to extract the name by introspection instead of looking for the object in the frame stack:: If `full` is True the full identifier of the object is preferred. In this case if `inner` is False the local-name for the object is found. If `inner` is True, find the import-name. If `safe` is True, returned value is converted -if it is not- into a valid Python identifier, though you should not trust this identifier resolves to the value. See `the examples in the documentation <name-of-narrative>`:ref:. ''' # XXX: The examples are stripped from here. Go the documentation page. from numbers import Number from xoutil.eight import range from xoutil.inspect import type_name arg_count = len(args) names = [[] for i in range(arg_count)] class vars: '`nonlocal` simulation' params = kwargs idx = 0 def grant(name=None, **again): if name: names[vars.idx].append(name) assert len(names[vars.idx]) < 5 if again: vars.params = dict(kwargs, **again) else: vars.params = kwargs vars.idx += 1 def param(name, default=False): return vars.params.get(name, default) while vars.idx < arg_count: item = args[vars.idx] if param('typed') and not type_name(item): item = type(item) if param('inner'): res = type_name(item) if res: if param('full'): head = module_name(item) if head: res = '.'.join((head, res)) grant(res) elif isinstance(item, (base_string, Number)): grant(str(item)) else: grant('@'.join(('%(next)s', hex(id(item)))), typed=True) else: import sys sf = sys._getframe(param('depth', 1)) try: i, LIMIT, res = 0, 5, _undef _full = param('full') while not res and sf and (i < LIMIT): key, mapping = _key_for_value(sf, item) if key and _full: head = module_name(_get_value(mapping, '__name__')) if not head: head = module_name(sf.f_code.co_name) if not head: head = module_name(item) or None else: head = None if key: res = key else: sf = sf.f_back i += 1 finally: # TODO: on "del sf" Python says "SyntaxError: can not delete # variable 'sf' referenced in nested scope". sf = None if res: grant('.'.join((head, res)) if head else res) else: res = type_name(item) if res: grant(res) else: grant(None, inner=True) for i in range(arg_count): names[i] = _get_best_name(names[i], safe=param('safe')) if arg_count == 0: return None elif arg_count == 1: return names[0] else: return names