+++ /dev/null
-"""Fixer for import statements.\r
-If spam is being imported from the local directory, this import:\r
- from spam import eggs\r
-Becomes:\r
- from .spam import eggs\r
-\r
-And this import:\r
- import spam\r
-Becomes:\r
- from . import spam\r
-"""\r
-\r
-# Local imports\r
-from .. import fixer_base\r
-from os.path import dirname, join, exists, sep\r
-from ..fixer_util import FromImport, syms, token\r
-\r
-\r
-def traverse_imports(names):\r
- """\r
- Walks over all the names imported in a dotted_as_names node.\r
- """\r
- pending = [names]\r
- while pending:\r
- node = pending.pop()\r
- if node.type == token.NAME:\r
- yield node.value\r
- elif node.type == syms.dotted_name:\r
- yield "".join([ch.value for ch in node.children])\r
- elif node.type == syms.dotted_as_name:\r
- pending.append(node.children[0])\r
- elif node.type == syms.dotted_as_names:\r
- pending.extend(node.children[::-2])\r
- else:\r
- raise AssertionError("unkown node type")\r
-\r
-\r
-class FixImport(fixer_base.BaseFix):\r
- BM_compatible = True\r
-\r
- PATTERN = """\r
- import_from< 'from' imp=any 'import' ['('] any [')'] >\r
- |\r
- import_name< 'import' imp=any >\r
- """\r
-\r
- def start_tree(self, tree, name):\r
- super(FixImport, self).start_tree(tree, name)\r
- self.skip = "absolute_import" in tree.future_features\r
-\r
- def transform(self, node, results):\r
- if self.skip:\r
- return\r
- imp = results['imp']\r
-\r
- if node.type == syms.import_from:\r
- # Some imps are top-level (eg: 'import ham')\r
- # some are first level (eg: 'import ham.eggs')\r
- # some are third level (eg: 'import ham.eggs as spam')\r
- # Hence, the loop\r
- while not hasattr(imp, 'value'):\r
- imp = imp.children[0]\r
- if self.probably_a_local_import(imp.value):\r
- imp.value = u"." + imp.value\r
- imp.changed()\r
- else:\r
- have_local = False\r
- have_absolute = False\r
- for mod_name in traverse_imports(imp):\r
- if self.probably_a_local_import(mod_name):\r
- have_local = True\r
- else:\r
- have_absolute = True\r
- if have_absolute:\r
- if have_local:\r
- # We won't handle both sibling and absolute imports in the\r
- # same statement at the moment.\r
- self.warning(node, "absolute and local imports together")\r
- return\r
-\r
- new = FromImport(u".", [imp])\r
- new.prefix = node.prefix\r
- return new\r
-\r
- def probably_a_local_import(self, imp_name):\r
- if imp_name.startswith(u"."):\r
- # Relative imports are certainly not local imports.\r
- return False\r
- imp_name = imp_name.split(u".", 1)[0]\r
- base_path = dirname(self.filename)\r
- base_path = join(base_path, imp_name)\r
- # If there is no __init__.py next to the file its not in a package\r
- # so can't be a relative import.\r
- if not exists(join(dirname(base_path), "__init__.py")):\r
- return False\r
- for ext in [".py", sep, ".pyc", ".so", ".sl", ".pyd"]:\r
- if exists(base_path + ext):\r
- return True\r
- return False\r