OLD | NEW |
(Empty) | |
| 1 """ |
| 2 Fixer for import statements, with a __future__ import line. |
| 3 |
| 4 Based on lib2to3/fixes/fix_import.py, but extended slightly so it also |
| 5 supports Cython modules. |
| 6 |
| 7 If spam is being imported from the local directory, this import: |
| 8 from spam import eggs |
| 9 becomes: |
| 10 from __future__ import absolute_import |
| 11 from .spam import eggs |
| 12 |
| 13 and this import: |
| 14 import spam |
| 15 becomes: |
| 16 from __future__ import absolute_import |
| 17 from . import spam |
| 18 """ |
| 19 |
| 20 from os.path import dirname, join, exists, sep |
| 21 from lib2to3.fixes.fix_import import FixImport |
| 22 from lib2to3.fixer_util import FromImport, syms |
| 23 from lib2to3.fixes.fix_import import traverse_imports |
| 24 |
| 25 from libfuturize.fixer_util import future_import |
| 26 |
| 27 |
| 28 class FixAbsoluteImport(FixImport): |
| 29 run_order = 9 |
| 30 |
| 31 def transform(self, node, results): |
| 32 """ |
| 33 Copied from FixImport.transform(), but with this line added in |
| 34 any modules that had implicit relative imports changed: |
| 35 |
| 36 from __future__ import absolute_import" |
| 37 """ |
| 38 if self.skip: |
| 39 return |
| 40 imp = results['imp'] |
| 41 |
| 42 if node.type == syms.import_from: |
| 43 # Some imps are top-level (eg: 'import ham') |
| 44 # some are first level (eg: 'import ham.eggs') |
| 45 # some are third level (eg: 'import ham.eggs as spam') |
| 46 # Hence, the loop |
| 47 while not hasattr(imp, 'value'): |
| 48 imp = imp.children[0] |
| 49 if self.probably_a_local_import(imp.value): |
| 50 imp.value = u"." + imp.value |
| 51 imp.changed() |
| 52 future_import(u"absolute_import", node) |
| 53 else: |
| 54 have_local = False |
| 55 have_absolute = False |
| 56 for mod_name in traverse_imports(imp): |
| 57 if self.probably_a_local_import(mod_name): |
| 58 have_local = True |
| 59 else: |
| 60 have_absolute = True |
| 61 if have_absolute: |
| 62 if have_local: |
| 63 # We won't handle both sibling and absolute imports in the |
| 64 # same statement at the moment. |
| 65 self.warning(node, "absolute and local imports together") |
| 66 return |
| 67 |
| 68 new = FromImport(u".", [imp]) |
| 69 new.prefix = node.prefix |
| 70 future_import(u"absolute_import", node) |
| 71 return new |
| 72 |
| 73 def probably_a_local_import(self, imp_name): |
| 74 """ |
| 75 Like the corresponding method in the base class, but this also |
| 76 supports Cython modules. |
| 77 """ |
| 78 if imp_name.startswith(u"."): |
| 79 # Relative imports are certainly not local imports. |
| 80 return False |
| 81 imp_name = imp_name.split(u".", 1)[0] |
| 82 base_path = dirname(self.filename) |
| 83 base_path = join(base_path, imp_name) |
| 84 # If there is no __init__.py next to the file its not in a package |
| 85 # so can't be a relative import. |
| 86 if not exists(join(dirname(base_path), "__init__.py")): |
| 87 return False |
| 88 for ext in [".py", sep, ".pyc", ".so", ".sl", ".pyd", ".pyx"]: |
| 89 if exists(base_path + ext): |
| 90 return True |
| 91 return False |
| 92 |
OLD | NEW |