From 1bae8359d4ad986e458e9397c11941adaf085f95 Mon Sep 17 00:00:00 2001 From: Tim Vieira Date: Mon, 5 Aug 2013 15:31:48 -0400 Subject: [PATCH] Big improvements to code coverage! --- .coveragerc | 26 ++++ src/Dyna/Backend/Python/aggregator.py | 12 +- src/Dyna/Backend/Python/chart.py | 4 +- src/Dyna/Backend/Python/interpreter.py | 14 +- src/Dyna/Backend/Python/prioritydict.py | 20 +-- src/Dyna/Backend/Python/repl.py | 2 +- src/Dyna/Backend/Python/term.py | 12 +- test/repl/aggregators.dynadoc | 94 ++++++++++++++ test/repl/boolean-aggregators.dynadoc | 45 ++++++- test/repl/list.dynadoc | 18 +++ test/repl/repl-misc.dynadoc | 121 ++++++++++++++++++ ...egator.dyna => retract-aggregator.dynadoc} | 0 12 files changed, 330 insertions(+), 38 deletions(-) create mode 100644 .coveragerc create mode 100644 test/repl/aggregators.dynadoc create mode 100644 test/repl/repl-misc.dynadoc rename test/repl/{retract-aggregator.dyna => retract-aggregator.dynadoc} (100%) diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..6cf9822 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,26 @@ +# .coveragerc to control coverage.py +[run] +branch = True + +[report] +# Regexes for lines to exclude from consideration +exclude_lines = + # Have to re-enable the standard pragma + pragma: no cover + + # Don't complain about missing debug-only code: + #def __repr__ + #if self\.debug + + # Don't complain if tests don't hit defensive assertion code: + raise AssertionError + raise NotImplementedError + + # Don't complain if non-runnable code isn't run: + if 0: + if __name__ == .__main__.: + +ignore_errors = True + +[html] +directory = coverage_html_report diff --git a/src/Dyna/Backend/Python/aggregator.py b/src/Dyna/Backend/Python/aggregator.py index 9794891..685080d 100644 --- a/src/Dyna/Backend/Python/aggregator.py +++ b/src/Dyna/Backend/Python/aggregator.py @@ -23,13 +23,13 @@ class NoAggregatorError(Exception): class Aggregator(object): def fold(self): - raise AggregatorError("item doesn't have an aggregator.") + raise NotImplementedError('') def inc(self, _val, _ruleix, _variables): - pass + raise NotImplementedError('') def dec(self, _val, _ruleix, _variables): - pass + raise NotImplementedError('') def clear(self): - pass + raise NotImplementedError('') NoAggregator = Aggregator() @@ -43,7 +43,7 @@ class BAggregator(Counter, Aggregator): def dec(self, val, _ruleix, _variables): self[val] -= 1 def fromkeys(self, *_): - assert False, "This method should never be called." + raise NotImplementedError("This method should never be called.") def empty(self): return not any(m > 0 for m in self.itervalues()) @@ -100,7 +100,7 @@ class DictEquals(BAggregator): class majority_equals(BAggregator): def fold(self): - [(k,c)] = self.most_common(1) + [(k,c)] = self.most_common(1) # how are ties handled? if c > 0: return k diff --git a/src/Dyna/Backend/Python/chart.py b/src/Dyna/Backend/Python/chart.py index 505ff2d..1604747 100644 --- a/src/Dyna/Backend/Python/chart.py +++ b/src/Dyna/Backend/Python/chart.py @@ -29,13 +29,13 @@ class Chart(object): heading = [self.name, '='*len(self.name)] - # special handing or-equals aggregators -- only list true facts (and errors) + # special handing `:-` aggregator -- only list true facts (and errors) if self.agg_name == ':-': lines = [] for term in sorted(rows): if term.value is true: lines.append('%s.' % _repr(term)) - elif term.value: # e.g. $error + else: # e.g. $error lines.append('%s = %s.' % (_repr(term), _repr(term.value))) if self.arity != 0: lines = heading + lines # heading diff --git a/src/Dyna/Backend/Python/interpreter.py b/src/Dyna/Backend/Python/interpreter.py index 73ef031..4f5c50d 100644 --- a/src/Dyna/Backend/Python/interpreter.py +++ b/src/Dyna/Backend/Python/interpreter.py @@ -377,6 +377,7 @@ class Interpreter(object): def run_uninitialized(self): q = set(self.uninitialized_rules) failed = [] + # run to fixed point while q: rule = q.pop() try: @@ -533,7 +534,7 @@ class Interpreter(object): if isinstance(item, Rule): continue (v, es) = x - self.error[item] = (v, [(e, h) for e, h in es if h is None or h.rule.index == rule.index]) + self.error[item] = (v, [(e, h) for e, h in es if h is None or h.rule == rule]) self.recompute_coarse() @@ -577,10 +578,7 @@ class Interpreter(object): # Communication with Dyna compiler def dynac(self, filename): - """ - Compile a file full of dyna code. Note: this routine does not pass along - parser_state. - """ + "Compile a string of dyna code." return self.compiler.dynac(filename) def dynac_code(self, code): @@ -660,7 +658,7 @@ class Interpreter(object): print >> out # errors pertaining to rules - for r in sorted(E, key=lambda r: r.index): + for r in sorted(E): print >> out, 'Error(s) in rule %s:' % r.index, r.span print >> out for line in r.src.split('\n'): @@ -692,7 +690,7 @@ class Interpreter(object): if self.uninitialized_rules: print >> out, red % 'Uninitialized rules' print >> out, red % '===================' - for rule in sorted(self.uninitialized_rules, key=lambda r: r.index): + for rule in sorted(self.uninitialized_rules): e = self.error[rule] print >> out, 'Failed to initialize rule:' print >> out, ' ', rule.src @@ -704,7 +702,7 @@ class Interpreter(object): if self.recompile: print >> out, red % 'Failed to recompile' print >> out, red % '===================' - for rule in sorted(self.recompile, key=lambda r: r.index): + for rule in sorted(self.recompile): e = self.error[rule] print >> out, 'Failed to recompile rule:' print >> out, ' ', rule.src diff --git a/src/Dyna/Backend/Python/prioritydict.py b/src/Dyna/Backend/Python/prioritydict.py index fe1424a..454dfb0 100644 --- a/src/Dyna/Backend/Python/prioritydict.py +++ b/src/Dyna/Backend/Python/prioritydict.py @@ -33,28 +33,20 @@ class prioritydict(dict): self._heap = [(v, k) for k, v in self.iteritems()] heapify(self._heap) - def smallest(self): - """ - Return the item with the lowest priority. - - Raises IndexError if the object is empty. - """ - heap = self._heap - v, k = heap[0] - while k not in self or self[k] != v: - heappop(heap) - v, k = heap[0] - return k - def pop_smallest(self): """ Return the item with the lowest priority and remove it. Raises IndexError if the object is empty. """ + + # Implementation note: Since we don't eagerly remove an element when + # it's priority changes, we need to filter our pops to make sure the + # priority isn't stale. + heap = self._heap v, k = heappop(heap) - while k not in self or self[k] != v: + while k not in self or self[k] != v: # while `k` is stale v, k = heappop(heap) del self[k] return k diff --git a/src/Dyna/Backend/Python/repl.py b/src/Dyna/Backend/Python/repl.py index 8c2304b..cb5800d 100644 --- a/src/Dyna/Backend/Python/repl.py +++ b/src/Dyna/Backend/Python/repl.py @@ -531,7 +531,7 @@ class REPL(cmd.Cmd, object): """ if not q.strip(): - print 'No query specified. Type `help trace` for usage information.' + print 'No query specified. Type `help trace` for usage.' return if q.endswith('.'): diff --git a/src/Dyna/Backend/Python/term.py b/src/Dyna/Backend/Python/term.py index f46f625..f2b2387 100644 --- a/src/Dyna/Backend/Python/term.py +++ b/src/Dyna/Backend/Python/term.py @@ -12,8 +12,8 @@ class Term(object): self.value = None self.aggregator = None - def __eq__(self, other): - return self is other +# def __eq__(self, other): +# return self is other def __cmp__(self, other): if self is other: @@ -75,8 +75,8 @@ class Cons(NoIntern, Term): else: yield a, (None,), a - def __iter__(self): - return iter(self.aslist) +# def __iter__(self): +# return iter(self.aslist) class Error(NoIntern, Term): @@ -97,8 +97,8 @@ class _Nil(Term): def like_chart(self): return iter([]) - def __iter__(self): - return iter([]) +# def __iter__(self): +# return iter([]) Nil = _Nil() diff --git a/test/repl/aggregators.dynadoc b/test/repl/aggregators.dynadoc new file mode 100644 index 0000000..312922c --- /dev/null +++ b/test/repl/aggregators.dynadoc @@ -0,0 +1,94 @@ +> a majority= 1. +| a majority= 1. +| a majority= 1. +| a majority= 2. +| a majority= 2. + +Changes +======= +a = 1. + +%> rules +%Rules +%===== +% 0: a majority= 1. +% 1: a majority= 1. +% 2: a majority= 1. +% 3: a majority= 2. +% 4: a majority= 2. + + +% ties are broken arbitrarily +> retract_rule 0 +> retract_rule 1 + +Changes +======= +a = 2. + +% retract remaining rules to make sure the aggregator goes null +> retract_rule 2 +> retract_rule 3 +> retract_rule 4 + +Changes +======= +a = null. + + +> a mean= 1. +| a mean= 2. +| a mean= 3. + +Changes +======= +a = 2.0. + +%> rules +% +%Rules +%===== +% 5: a mean= 1. +% 6: a mean= 2. +% 7: a mean= 3. + +> retract_rule 5 + +Changes +======= +a = 2.5. + +> retract_rule 6 + +Changes +======= +a = 3.0. + +> retract_rule 7 + +Changes +======= +a = null. + + + +% A few simple tests for `*=` + +> a *= 3. +| a *= 3. + +Changes +======= +a = 9. + +> retract_rule 8 + +Changes +======= +a = 3. + +> retract_rule 9 + +Changes +======= +a = null. diff --git a/test/repl/boolean-aggregators.dynadoc b/test/repl/boolean-aggregators.dynadoc index 4ad4c43..105cea1 100644 --- a/test/repl/boolean-aggregators.dynadoc +++ b/test/repl/boolean-aggregators.dynadoc @@ -36,6 +36,18 @@ e = $error. >>> 1 new errors. Type `sol` for details. +> sol + +Solution +======== +e = $error. + +Errors +====== +Error(s) aggregating e/0: + TypeError: + `e`: false is not true. + > e :- true. @@ -135,4 +147,35 @@ c = true. f/2 === f(1,2). -f(2,2). \ No newline at end of file +f(2,2). + + +% type checking for `|=` + +> foo |= 10. + +Changes +======= +foo = $error. +>>> 1 new errors. Type `sol` for details. + + +> goo &= true. + +Changes +======= +goo = true. + +> goo &= false. + +Changes +======= +goo = false. + + +> goo &= 10. + +Changes +======= +goo = $error. +>>> 1 new errors. Type `sol` for details. diff --git a/test/repl/list.dynadoc b/test/repl/list.dynadoc index fa91a02..a742f34 100644 --- a/test/repl/list.dynadoc +++ b/test/repl/list.dynadoc @@ -150,3 +150,21 @@ Changes ======= thingsbag = [true, 1, 1, 2, "three"]. thingset = [true, 1, 2, "three"]. + + +% comparison operator +> foobar([]). +| foobar([1,2]). +| foobar([1,3]). +| foobar("a"). +| foobar(&a, &b). +| foobar(&a, &c). + +Changes +======= +foobar("a") = true. +foobar([1, 2]) = true. +foobar([1, 3]) = true. +foobar([]) = true. +foobar(a,b) = true. +foobar(a,c) = true. diff --git a/test/repl/repl-misc.dynadoc b/test/repl/repl-misc.dynadoc new file mode 100644 index 0000000..82af397 --- /dev/null +++ b/test/repl/repl-misc.dynadoc @@ -0,0 +1,121 @@ +> rules + +No rules found. + +> a += 1. + +Changes +======= +a = 1. + +> rules + +Rules +===== + 0: a += 1. + +> a += 1 + +ERROR: Line doesn't end with period. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Retract rule + +> retract_rule asdf + +Please specify an integer. Type `help retract_rule` to read more. + +> retract_rule 1000 + +Rule 1000 not found. +List available by typing `rules` + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Query + +> query + +No query specified. Type `help query` for usage. + +> query a. + +Queries don't end with a dot. + +> query a + +a = 1. + +%%% TODO: a query with an error > query a/0 + +> query xxxx + +No results. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% vquery + +> vquery + +No query specified. Type `help query` for usage. + +> vquery a. + +Queries don't end with a dot. + +> vquery a + +1 where {} + +> vquery xxxx + +No results. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% trace + +> trace + +No query specified. Type `help trace` for usage. + +> trace a. + +Queries don't end with a dot. + +> trace xxxx + +no items matching `xxxx`. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Help + +> help query + + Query solution. + + Consider the following example; + > f(1) := 1. + > f(2) := 4. + + There a few versions of query: + + - `vquery` shows variable bindings + > vquery f(X) + 1 where {X=1} + 4 where {X=1} + + - `query` shows variable bindings applied to query + > query f(X) + f(1) = 1. + f(2) = 4. + + - `trace` is an introspection tool for visualizing the derivation of an + item and its value. Type `help trace` for more information. + +> help vquery + +See query. diff --git a/test/repl/retract-aggregator.dyna b/test/repl/retract-aggregator.dynadoc similarity index 100% rename from test/repl/retract-aggregator.dyna rename to test/repl/retract-aggregator.dynadoc -- 2.50.1