# HG changeset patch # User Paul Boddie # Date 1271617841 -7200 # Node ID 8edbe04145ad28b63b8c8ea5c0bc62da7f05c830 # Parent 3963e69fa3cc4d4e663e473bad1eafc7b4fc939c Moved a test into the failure category. Adjusted the docstring for the multiple candidate usage case test. Added a module for generating class summaries. diff -r 3963e69fa3cc -r 8edbe04145ad micropython/report.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/micropython/report.py Sun Apr 18 21:10:41 2010 +0200 @@ -0,0 +1,261 @@ +#!/usr/bin/env python + +""" +View annotated sources. + +Copyright (C) 2006, 2007, 2010 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +from micropython.data import * +from compiler.visitor import ASTVisitor +import sys +import os +import textwrap + +# Classes. + +# HTML-related output production. + +html_header = """ + + + + Module + + + +""" + +html_footer = """ + +""" + +# Utility classes. + +class Writer: + + "A utility class providing useful HTML output methods." + + # Methods which return strings. + + def _text(self, text): + return text.replace("&", "&").replace("<", "<").replace(">", ">") + + def _attr(self, attr): + return self._text(attr).replace("'", "'").replace('"', """) + + def _url(self, url): + return self._attr(url).replace("#", "%23").replace("-", "%2d") + + def _summary_link(self, module_name, name): + return "%s" % (module_name, os.path.extsep, self._attr(name), self._text(name)) + + # Methods which write to the stream. + + def _comment(self, comment): + self.stream.write("# %s\n" % comment) + + def _keyword(self, kw): + self.stream.write("%s " % kw) + + def _doc(self, node): + if node.doc is not None: + self.stream.write("
\n")
+            self.stream.write('"""')
+            output = textwrap.dedent(node.doc.replace('"""', '\\"\\"\\"'))
+            self.stream.write(self._text(output))
+            self.stream.write('"""')
+            self.stream.write("
\n") + + def _name(self, name): + self.stream.write("%s\n" % name) + +# Summary classes. + +class Summariser(Writer): + + def __init__(self, stream): + self.stream = stream + + def process(self, module): + self.module = module + self._init_details() + self.stream.write(html_header) + self._write_classes(module) + self.stream.write(html_footer) + + def _write_classes(self, module): + self.stream.write("\n") + + all_classes = {} + + for obj in self.module.all_objects: + if isinstance(obj, Class): + all_classes[obj.name] = obj + + all_class_names = all_classes.keys() + all_class_names.sort() + + for name in all_class_names: + self._write_class(all_classes[name]) + + self.stream.write("
\n") + + def _write_class(self, obj): + + # Write the class... + + self.stream.write("\n") + self.stream.write("\n") + self.stream.write("\n" % obj.full_name()) + self._keyword("class") + self.stream.write(obj.name) + self.stream.write("\n") + + # ...and all known attribute names. + + obj_attributes = obj.all_attribute_names() + + for name in self.attribute_names: + if name in obj_attributes: + self.stream.write("%s\n" % self._text(name)) + else: + self.stream.write("\n") + self.stream.write("\n") + + self.stream.write("\n") + + def _init_details(self): + names = set() + + # Visit all classes. + + for obj in self.module.all_objects: + if isinstance(obj, Class): + names.update(obj.all_attribute_names()) + + self.attribute_names = list(names) + self.attribute_names.sort() + +# Convenience functions. + +def summary(module, filename): + stream = open(filename, "wb") + try: + summariser = Summariser(stream) + summariser.process(module) + finally: + stream.close() + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 3963e69fa3cc -r 8edbe04145ad tests/abandoned_attribute_usage_multiple_candidates.py --- a/tests/abandoned_attribute_usage_multiple_candidates.py Sun Mar 28 01:12:15 2010 +0100 +++ b/tests/abandoned_attribute_usage_multiple_candidates.py Sun Apr 18 21:10:41 2010 +0200 @@ -2,9 +2,9 @@ """ This test attempts to cause the recording of the usage of 'C' in the function -'f', alongside the expectation that 'D' might be used instead. A guard -stipulating constraints for all of 'f' cannot therefore be generated. Meanwhile, -the method 'E.h' should be eliminated. +'f', alongside the expectation that 'D' might be used instead with the function +'g'. A guard cannot therefore be generated. Meanwhile, the method 'E.h' should +be eliminated. """ class C: diff -r 3963e69fa3cc -r 8edbe04145ad tests/attribute_access_type_restriction_neither.py --- a/tests/attribute_access_type_restriction_neither.py Sun Mar 28 01:12:15 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -#!/usr/bin/env python - -class C: - def f(self): - return 1 - -class D: - def f(self): - return 2 - - def g(self): - return 3 - -class E: # unused - def f(self): - return 4 - - def h(self): - return 5 - -def test_neither(obj, obj2): - # obj: - # obj2: - if 0: - obj.g() # D (g) - else: - obj.f() # C, D, E (f) - # # (g) ^ (f) - return 4 - -c = C() -d = D() -result1_4 = test_neither(c, d) - -# vim: tabstop=4 expandtab shiftwidth=4 diff -r 3963e69fa3cc -r 8edbe04145ad tests/failure/attribute_access_type_restriction_new_impossible.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/failure/attribute_access_type_restriction_new_impossible.py Sun Apr 18 21:10:41 2010 +0200 @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +class C: + def f(self): + return 1 + +class D: + def f(self): + return 2 + + def g(self): # unused + return 3 + +class E: + def f(self): + return 4 + + def h(self): + return 5 + +def test_new(obj): + # obj: C, D, E (f) + if obj.f(): # C, D, E (f) + obj2 = D() # obj2: E (h) -> conflict! + obj2.h() # E (h) + # else: + # ... # obj: C, D, E (f) + # # (f) ^ (f) + return obj.f() # C, D, E (f) + +c = C() +d = D() +e = E() +result2_2 = test_new(c) + +# vim: tabstop=4 expandtab shiftwidth=4