# HG changeset patch # User Paul Boddie # Date 1192920800 -7200 # Node ID 12f98130428ced83b57bcbc4cb917cc1bf19c688 # Parent 3699ff87d748730259e89041125bfaf00bde0716 Added module_name to various objects, along with a full_name method in a Naming mix-in class, and a __repr__ method for more informative output. Added attribute listing methods to Class. Introduced more flexible handling of missing modules in visitFrom, visitGetattr and visitImport. Added missing AST node visitor methods and built-in types. Added testing of programs to the test script. diff -r 3699ff87d748 -r 12f98130428c micropython/__init__.py --- a/micropython/__init__.py Sat Oct 20 01:36:44 2007 +0200 +++ b/micropython/__init__.py Sun Oct 21 00:53:20 2007 +0200 @@ -27,6 +27,7 @@ importer = Importer(sys.path) importer.load_from_file(filename) +importer.vacuum() Such importer objects are the most convenient mechanism through which the functionality of the micropython package may be accessed. @@ -152,10 +153,10 @@ package exists. """ + if self.modules.has_key(name) and self.modules[name].loaded: + #print "Cached (%s)" % name + return self.modules[name] print "Loading", name - if self.modules.has_key(name) and self.modules[name].loaded: - print "Cached", name - return self.modules[name] # Split the name into path components, and try to find the uppermost in # the search path. @@ -163,7 +164,7 @@ path = name.split(".") m = self.find_in_path(path[0]) if not m: - print "Not found", path[0] + print "Not found (%s)" % path[0] return None # NOTE: Import error. d, filename = m @@ -176,7 +177,7 @@ if len(path) > 1: if not d: - print "No package", filename + print "No package (%s)" % filename return None # NOTE: Import error (package not found). else: self.add_submodules(d, module) @@ -189,7 +190,7 @@ m = self.find(d, p) if not m: - print "Not found", p + print "Not found (%s)" % p return None # NOTE: Import error. d, filename = m module_name = ".".join(path_so_far) @@ -225,15 +226,15 @@ module = self.add_module(module_name) if not module.loaded and module not in self.loading: self.loading.add(module) - print "Parsing", name + #print "Parsing", name module.parse(name) - print "Done", name + #print "Done", name self.loading.remove(module) module.loaded = 1 # Record the module. - print "Loaded", module_name #, "with namespace", module.namespace.keys() + #print "Loaded", module_name, "with namespace", module.namespace.keys() return module def add_module(self, module_name): diff -r 3699ff87d748 -r 12f98130428c micropython/inspect.py --- a/micropython/inspect.py Sat Oct 20 01:36:44 2007 +0200 +++ b/micropython/inspect.py Sun Oct 21 00:53:20 2007 +0200 @@ -42,12 +42,23 @@ def keys(self): return self.namespace.keys() -class Class(NamespaceDict): +class Naming: + + "A mix-in providing naming conveniences." + + def full_name(self): + if self.name is not None: + return self.module_name + "." + self.name + else: + return self.module_name + +class Class(NamespaceDict, Naming): "An inspected class." - def __init__(self, name): + def __init__(self, name, module_name): self.name = name + self.module_name = module_name self.bases = [] self.namespace = {} self.instattr = set() @@ -55,25 +66,66 @@ def add_base(self, base): self.bases.append(base) -class Function(NamespaceDict): + def __repr__(self): + return "Class(%r, %r)" % (self.name, self.module_name) + + def class_attributes(self): + + "Return all class attributes, indicating the class which provides them." + + attr = {} + reversed_bases = self.bases[:] + reversed_bases.reverse() + for cls in reversed_bases: + attr.update(cls.class_attributes()) + for name, value in self.namespace.items(): + attr[name] = self.full_name() + return attr + + def instance_attributes(self): + + """ + Return all attributes for an instance, indicating either the class which + provides them or that the instance itself provides them. + """ + + attr = {} + attr.update(self.class_attributes()) + for name in self.instattr: + if attr.has_key(name): + print "Instance attribute", name, "overrides class attribute." + attr[name] = None + return attr + +class Function(NamespaceDict, Naming): "An inspected function." - def __init__(self, name, argnames, has_star, has_dstar): + def __init__(self, name, module_name, argnames, has_star, has_dstar): self.name = name + self.module_name = module_name self.argnames = argnames self.has_star = has_star self.has_dstar = has_dstar self.namespace = {} -class UnresolvedName(NamespaceDict): + def __repr__(self): + return "Function(%r, %r, %r, %r, %r)" % ( + self.name, self.module_name, self.argnames, self.has_star, self.has_dstar + ) + +class UnresolvedName(NamespaceDict, Naming): "A module, class or function which was mentioned but could not be imported." - def __init__(self, name): + def __init__(self, name, module_name): self.name = name + self.module_name = module_name self.namespace = {} + def __repr__(self): + return "UnresolvedName(%r, %r)" % (self.name, self.module_name) + class Module(ASTVisitor, NamespaceDict): "An inspected module." @@ -120,6 +172,12 @@ if isinstance(value, Module) and not value.loaded: del self.namespace[name] + def full_name(self): + return self.name + + def __repr__(self): + return "Module(%r)" % self.name + # Namespace methods. def store(self, name, obj): @@ -148,6 +206,8 @@ visitAnd = NOP + visitAssert = NOP + def visitAssign(self, node): self.expr = self.dispatch(node.expr) for n in node.nodes: @@ -173,21 +233,27 @@ visitAugAssign = NOP + visitBackquote = NOP + visitBitand = NOP visitBitor = NOP + visitBitxor = NOP + + visitBreak = NOP + visitCallFunc = NOP def visitClass(self, node): if not self.in_global: - raise InspectError, "Class is %s not global: cannot handle this reasonably." % node.name + print "Class %r in %r is not global: ignored." % (node.name, self) else: - cls = Class(node.name) + cls = Class(node.name, self.name) for base in node.bases: base_ref = self.dispatch(base) if base_ref is None: - raise InspectError, "Base class %s for class %s is not found: it may be hidden in some way." % (base, node.name) + raise InspectError, "Base class %r for class %r in %r is not found: it may be hidden in some way." % (base, self, cls) cls.add_base(base_ref) # Make an entry for the class. @@ -200,12 +266,28 @@ return node + visitCompare = NOP + visitConst = NOP + visitContinue = NOP + + visitDecorators = NOP + visitDict = NOP visitDiscard = NOP + visitDiv = NOP + + visitEllipsis = NOP + + visitExec = NOP + + visitExpression = NOP + + visitFloorDiv = NOP + visitFor = NOP def visitFrom(self, node): @@ -219,12 +301,12 @@ for name, alias in node.names: if name != "*": - if module is not None: + if module is not None and module.namespace.has_key(name): self.namespace[alias or name] = attr = module.namespace[name] if isinstance(attr, Module) and not attr.loaded: self.importer.load(attr.name) else: - self.namespace[alias or name] = UnresolvedName(name) + self.namespace[alias or name] = UnresolvedName(name, node.modname) else: if module is not None: for n in module.namespace.keys(): @@ -237,6 +319,7 @@ def visitFunction(self, node): function = Function( node.name, + self.name, node.argnames, has_star=(node.flags & 4 != 0), has_dstar=(node.flags & 8 != 0) @@ -253,12 +336,24 @@ self.store(node.name, function) return None + visitGenExpr = NOP + + visitGenExprFor = NOP + + visitGenExprIf = NOP + + visitGenExprInner = NOP + def visitGetattr(self, node): expr = self.dispatch(node.expr) - if expr is not None and isinstance(expr, Module): - return expr.namespace.get(node.attrname) - else: - return builtins_namespace.get(node.attrname) + if expr is not None: + if isinstance(expr, Module): + return expr.namespace.get(node.attrname) + elif isinstance(expr, UnresolvedName): + return UnresolvedName(node.attrname, expr.full_name()) + return builtins_namespace.get(node.attrname) + + visitGlobal = NOP def visitIf(self, node): for test, body in node.tests: @@ -273,23 +368,35 @@ for name, alias in node.names: if alias is not None: - self.namespace[alias] = self.importer.load(name, 1) + self.namespace[alias] = self.importer.load(name, 1) or UnresolvedName(None, name) else: - self.namespace[name.split(".")[0]] = self.importer.load(name) + self.namespace[name.split(".")[0]] = self.importer.load(name) or UnresolvedName(None, name.split(".")[0]) return None + visitInvert = NOP + + visitKeyword = NOP + + visitLambda = NOP + visitLeftShift = NOP visitList = NOP + visitListComp = NOP + + visitListCompFor = NOP + + visitListCompIf = NOP + + visitMod = NOP + def visitModule(self, node): return self.dispatch(node.node) visitMul = NOP - visitMod = NOP - def visitName(self, node): name = node.name if name == "self": @@ -307,15 +414,27 @@ visitPass = NOP + visitPower = NOP + + visitPrint = NOP + + visitPrintnl = NOP + visitRaise = NOP + visitReturn = NOP + visitRightShift = NOP + visitSlice = NOP + def visitStmt(self, node): for n in node.nodes: self.dispatch(n) return None + visitSub = NOP + visitSubscript = NOP def visitTryExcept(self, node): @@ -326,14 +445,28 @@ self.dispatch(node.else_) return None + visitTryFinally = NOP + visitTuple = NOP + visitUnaryAdd = NOP + + visitUnarySub = NOP + + visitWhile = NOP + + visitWith = NOP + + visitYield = NOP + class Self: "A reference to an object within a method." pass +# Built-in types initialisation. + builtins_namespace = {} for key in ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'DeprecationWarning', 'EOFError', 'Ellipsis', @@ -348,7 +481,9 @@ 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', - 'ValueError', 'Warning', 'ZeroDivisionError', 'object']: - builtins_namespace[key] = Class(key) + 'ValueError', 'Warning', 'ZeroDivisionError', + 'bool', 'buffer', 'complex', 'dict', 'file', 'float', 'int', 'list', + 'long', 'object', 'slice', 'str', 'tuple', 'type', 'unicode']: + builtins_namespace[key] = Class(key, "__builtins__") # vim: tabstop=4 expandtab shiftwidth=4 diff -r 3699ff87d748 -r 12f98130428c test.py --- a/test.py Sat Oct 20 01:36:44 2007 +0200 +++ b/test.py Sun Oct 21 00:53:20 2007 +0200 @@ -2,9 +2,14 @@ import micropython import sys + i = micropython.Importer(sys.path) -m = i.load("micropython") -#m = i.load_from_file("micropython/__init__.py") -i.vacuum() +if len(sys.argv) < 2: + m = i.load("micropython") + #m = i.load_from_file("micropython/__init__.py") + i.vacuum() +else: + m = i.load_from_file(sys.argv[1]) + i.vacuum() # vim: tabstop=4 expandtab shiftwidth=4