1.1 --- a/micropython/common.py Tue Oct 08 22:44:44 2013 +0200
1.2 +++ b/micropython/common.py Tue Oct 08 22:59:10 2013 +0200
1.3 @@ -230,6 +230,47 @@
1.4
1.5 return targets
1.6
1.7 +def get_module_name(node, module):
1.8 +
1.9 + """
1.10 + Using the given From 'node' and 'module' in which it is found, calculate
1.11 + any relative import information, returning a tuple containing a module
1.12 + to import along with any names to import based on the node's name
1.13 + information.
1.14 +
1.15 + Where the returned module is given as None, whole module imports should
1.16 + be performed for the returned modules using the returned names.
1.17 + """
1.18 +
1.19 + # Absolute import.
1.20 +
1.21 + if node.level == 0:
1.22 + return node.modname, node.names
1.23 +
1.24 + # Relative to this module.
1.25 +
1.26 + elif node.level == 1:
1.27 + basename = module.full_name()
1.28 +
1.29 + # Relative to an ancestor of this module.
1.30 +
1.31 + else:
1.32 + path = module.full_name().split(".")
1.33 + if node.level > len(path):
1.34 + raise InspectError("Relative import %r involves too many levels up from module %r" % (
1.35 + ("." * node.level + node.modname), module.full_name()))
1.36 + basename = ".".join(path[:-node.level+1])
1.37 +
1.38 + # Name imports from a module.
1.39 +
1.40 + if node.modname:
1.41 + return "%s.%s" % (basename, node.modname), node.names
1.42 +
1.43 + # Relative whole module imports.
1.44 +
1.45 + else:
1.46 + return None, [("%s.%s" % (basename, name), alias) for name, alias in node.names]
1.47 +
1.48 def used_by_unit(node):
1.49
1.50 """
2.1 --- a/micropython/inspect.py Tue Oct 08 22:44:44 2013 +0200
2.2 +++ b/micropython/inspect.py Tue Oct 08 22:59:10 2013 +0200
2.3 @@ -72,7 +72,7 @@
2.4 benefits in considering a local to be constant within a single invocation.
2.5 """
2.6
2.7 -from micropython.common import ASTVisitor, operator_functions
2.8 +from micropython.common import ASTVisitor, operator_functions, get_module_name
2.9 from micropython.data import *
2.10 from micropython.errors import *
2.11 import compiler.ast
2.12 @@ -224,7 +224,7 @@
2.13 # Module import declarations.
2.14
2.15 elif isinstance(n, compiler.ast.From):
2.16 - modname, names = self.get_module_name(n)
2.17 + modname, names = get_module_name(n, self)
2.18
2.19 # Perform whole module relative imports.
2.20
2.21 @@ -262,45 +262,6 @@
2.22 else:
2.23 self.process_structure(n)
2.24
2.25 - def get_module_name(self, node):
2.26 -
2.27 - """
2.28 - Using the given From 'node', calculate any relative import information,
2.29 - returning a tuple containing a module to import along with any names to
2.30 - import based on the node's name information.
2.31 -
2.32 - Where the returned module is given as None, whole module imports should
2.33 - be performed for the returned modules using the returned names.
2.34 - """
2.35 -
2.36 - # Absolute import.
2.37 -
2.38 - if node.level == 0:
2.39 - return node.modname, node.names
2.40 -
2.41 - # Relative to this module.
2.42 -
2.43 - elif node.level == 1:
2.44 - basename = self.full_name()
2.45 -
2.46 - # Relative to an ancestor of this module.
2.47 -
2.48 - else:
2.49 - path = self.full_name().split(".")
2.50 - if node.level > len(path):
2.51 - raise InspectError("Relative import %r involves too many levels up from module %r" % (("." * node.level + node.modname), self.full_name()))
2.52 - basename = ".".join(path[:-node.level+1])
2.53 -
2.54 - # Name imports from a module.
2.55 -
2.56 - if node.modname:
2.57 - return "%s.%s" % (basename, node.modname), node.names
2.58 -
2.59 - # Relative whole module imports.
2.60 -
2.61 - else:
2.62 - return None, [("%s.%s" % (basename, name), alias) for name, alias in node.names]
2.63 -
2.64 def get_module_paths(self, name):
2.65
2.66 """
2.67 @@ -1174,7 +1135,7 @@
2.68 self.resume_broken_branches()
2.69
2.70 def visitFrom(self, node):
2.71 - modname, names = self.get_module_name(node)
2.72 + modname, names = get_module_name(node, self)
2.73
2.74 if not modname:
2.75 return self._visitImport(names)
3.1 --- a/micropython/report.py Tue Oct 08 22:44:44 2013 +0200
3.2 +++ b/micropython/report.py Tue Oct 08 22:59:10 2013 +0200
3.3 @@ -292,10 +292,10 @@
3.4 classes or "specific-ref", module_name, os.path.extsep,
3.5 self._attr(full_name), self._text(name)))
3.6
3.7 - def _module_link(self, module_name, classes=None):
3.8 + def _module_link(self, module_name, label, classes=None):
3.9 self.stream.write("<a class='%s' href='%s%sxhtml'>%s</a>" % (
3.10 classes or "name", module_name, os.path.extsep,
3.11 - self._text(module_name)))
3.12 + self._text(label)))
3.13
3.14 def _scope(self, scope, attr):
3.15 self.stream.write("<div class='scope'>"
3.16 @@ -815,17 +815,35 @@
3.17 def visitFrom(self, node):
3.18 self.stream.write("<div class='from nowrap'>\n")
3.19 self._keyword("from")
3.20 - self._module_link(node.modname)
3.21 +
3.22 + # Support relative imports of names and whole modules.
3.23 +
3.24 + modname, names = get_module_name(node, self.module)
3.25 + if modname:
3.26 + self._module_link(modname, "%s%s" % ("." * node.level, modname))
3.27 + else:
3.28 + self._text("." * node.level)
3.29 +
3.30 self._keyword("import", 1)
3.31 first = True
3.32 - for name, alias in node.names:
3.33 +
3.34 + # Integrate the provided name details with any calculated details
3.35 + # resulting from whole module imports.
3.36 +
3.37 + for (name, alias), (full_name, alias) in zip(node.names, names):
3.38 if not first:
3.39 self.stream.write(", ")
3.40 - self._name(name)
3.41 +
3.42 + if modname:
3.43 + self._name(name)
3.44 + else:
3.45 + self._module_link(full_name, name)
3.46 +
3.47 if alias:
3.48 self._keyword("as", 1)
3.49 self._name(alias)
3.50 first = False
3.51 +
3.52 self.stream.write("</div>\n")
3.53
3.54 def visitFunction(self, node):
3.55 @@ -902,7 +920,7 @@
3.56 for name, alias in node.names:
3.57 if not first:
3.58 self.stream.write(",\n")
3.59 - self._module_link(name)
3.60 + self._module_link(name, name)
3.61 if alias:
3.62 self._keyword("as", 1)
3.63 self._name(alias)