def test_ImportStatement_eqne_2():
    stmt1a = ImportStatement("from a import b")
    stmt1b = ImportStatement("from a import b")
    stmt2 = ImportStatement("from a import b as b")
    assert (stmt1a == stmt1b)
    assert not (stmt1a != stmt1b)
    assert (stmt1a != stmt2)
    assert not (stmt1a == stmt2)
示例#2
0
def test_ImportSet_constructor_list_importstmt_1():
    importset = ImportSet([
        ImportStatement("from m1 import a, b"),
        ImportStatement("from m1 import c as c")
    ])
    expected = [
        Import("from m1 import a"),
        Import("from m1 import b"),
        Import("from m1 import c")
    ]
    assert list(importset) == expected
def test_Import_from_Statement_1():
    imp = Import(ImportStatement("from foo import bar"))
    assert imp.fullname == "foo.bar"
    assert imp.import_as == "bar"
    assert imp.split == ImportSplit("foo", "bar", None)
    assert str(imp) == "from foo import bar"
    assert imp == Import("from foo import bar")
def test_ImportStatement_alias_1():
    stmt = ImportStatement("from foo  import bar  as  bar,   bar as   baz")
    assert stmt.fromname == "foo"
    assert stmt.aliases == (("bar", "bar"), ("bar", "baz"))
    assert stmt.imports == (Import(ImportSplit("foo", "bar", "bar")),
                            Import(ImportSplit("foo", "bar", "baz")))
    assert str(stmt) == "from foo import bar as bar, bar as baz"
def test_ImportStatement_relative_local_1():
    stmt = ImportStatement("from .  import bar , bar2 as baz2")
    assert stmt.fromname == "."
    assert stmt.aliases == (("bar", None), ("bar2", "baz2"))
    assert stmt.imports == (Import(ImportSplit(".", "bar", None)),
                            Import(ImportSplit(".", "bar2", "baz2")))
    assert str(stmt) == "from . import bar, bar2 as baz2"
示例#6
0
    def get_statements(self, separate_from_imports=True):
        """
        Canonicalized L{ImportStatement}s.
        These have been merged by module and sorted.

          >>> importset = ImportSet('''
          ...     import a, b as B, c, d.dd as DD
          ...     from __future__ import division
          ...     from _hello import there
          ...     from _hello import *
          ...     from _hello import world
          ... ''')

          >>> for s in importset.get_statements(): print(s)
          from __future__ import division
          import a
          import b as B
          import c
          from _hello import *
          from _hello import there, world
          from d import dd as DD

        @rtype:
          C{tuple} of L{ImportStatement}s
        """
        groups = self._by_module_name
        if not separate_from_imports:

            def union_dicts(*dicts):
                result = {}
                for label, dict in enumerate(dicts):
                    for k, v in six.iteritems(dict):
                        result[(k, label)] = v
                return result

            groups = [groups[0], union_dicts(*groups[1:])]
        result = []
        for importgroup in groups:
            for _, imports in sorted(importgroup.items()):
                star_imports, nonstar_imports = (partition(
                    imports, lambda imp: imp.import_as == "*"))
                assert len(star_imports) <= 1
                if star_imports:
                    result.append(ImportStatement(star_imports))
                if nonstar_imports:
                    result.append(ImportStatement(sorted(nonstar_imports)))
        return tuple(result)
def test_ImportStatement_multi_1():
    stmt = ImportStatement("from foo  import bar, bar2, bar")
    assert stmt.fromname == "foo"
    assert stmt.aliases == (("bar", None), ("bar2", None), ("bar", None))
    assert stmt.imports == (Import(ImportSplit("foo", "bar", None)),
                            Import(ImportSplit("foo", "bar2", None)),
                            Import(ImportSplit("foo", "bar", None)))
    assert str(stmt) == "from foo import bar, bar2, bar"
示例#8
0
 def _from_args(cls, args, ignore_nonimports=False, ignore_shadowed=False):
     """
     @type args:
       C{tuple} or C{list} of L{ImportStatement}s, L{PythonStatement}s,
       L{PythonBlock}s, L{FileText}, and/or L{Filename}s
     @param ignore_nonimports:
       If C{False}, complain about non-imports.  If C{True}, ignore
       non-imports.
     @param ignore_shadowed:
       See L{ImportSet.__new__}.
     @rtype:
       L{ImportSet}
     """
     if not isinstance(args, (tuple, list)):
         args = [args]
     # Filter empty arguments to allow the subsequent optimizations to work
     # more often.
     args = [a for a in args if a]
     if not args:
         return cls._EMPTY
     # If we only got one C{ImportSet}, just return it.
     if len(args) == 1 and type(args[0]) is cls and not ignore_shadowed:
         return args[0]
     # Collect all L{Import}s from arguments.
     imports = []
     for arg in args:
         if isinstance(arg, Import):
             imports.append(arg)
         elif isinstance(arg, ImportSet):
             imports.extend(arg.imports)
         elif isinstance(arg, ImportStatement):
             imports.extend(arg.imports)
         elif isinstance(arg, str) and is_identifier(arg, dotted=True):
             imports.append(Import(arg))
         else:  # PythonBlock, PythonStatement, Filename, FileText, str
             block = PythonBlock(arg)
             for statement in block.statements:
                 # Ignore comments/blanks.
                 if statement.is_comment_or_blank:
                     pass
                 elif statement.is_import:
                     imports.extend(ImportStatement(statement).imports)
                 elif ignore_nonimports:
                     pass
                 else:
                     raise NonImportStatementError(
                         "Got non-import statement %r" % (statement, ))
     return cls._from_imports(imports, ignore_shadowed=ignore_shadowed)
示例#9
0
 def _from_args(cls, args, ignore_nonimports=False, ignore_shadowed=False):
     """
     :type args:
       ``tuple`` or ``list`` of `ImportStatement` s, `PythonStatement` s,
       `PythonBlock` s, `FileText`, and/or `Filename` s
     :param ignore_nonimports:
       If ``False``, complain about non-imports.  If ``True``, ignore
       non-imports.
     :param ignore_shadowed:
       See `ImportSet.__new__`.
     :rtype:
       `ImportSet`
     """
     if not isinstance(args, (tuple, list)):
         args = [args]
     # Filter empty arguments to allow the subsequent optimizations to work
     # more often.
     args = [a for a in args if a]
     if not args:
         return cls._EMPTY
     # If we only got one ``ImportSet``, just return it.
     if len(args) == 1 and type(args[0]) is cls and not ignore_shadowed:
         return args[0]
     # Collect all `Import` s from arguments.
     imports = []
     for arg in args:
         if isinstance(arg, Import):
             imports.append(arg)
         elif isinstance(arg, ImportSet):
             imports.extend(arg.imports)
         elif isinstance(arg, ImportStatement):
             imports.extend(arg.imports)
         elif isinstance(arg, str) and is_identifier(arg, dotted=True):
             imports.append(Import(arg))
         else: # PythonBlock, PythonStatement, Filename, FileText, str
             block = PythonBlock(arg)
             for statement in block.statements:
                 # Ignore comments/blanks.
                 if statement.is_comment_or_blank:
                     pass
                 elif statement.is_import:
                     imports.extend(ImportStatement(statement).imports)
                 elif ignore_nonimports:
                     pass
                 else:
                     raise NonImportStatementError(
                         "Got non-import statement %r" % (statement,))
     return cls._from_imports(imports, ignore_shadowed=ignore_shadowed)
示例#10
0
def replace_star_imports(codeblock, params=None):
    r"""
    Replace lines such as::
      from foo.bar import *
    with
      from foo.bar import f1, f2, f3

    Note that this requires involves actually importing C{foo.bar}, which may
    have side effects.  (TODO: rewrite to avoid this?)

    The result includes all imports from the C{email} module.  The result
    excludes shadowed imports.  In this example:
      1. The original C{MIMEAudio} import is shadowed, so it is removed.
      2. The C{MIMEImage} import in the C{email} module is shadowed by a
         subsequent import, so it is omitted.

      >>> codeblock = PythonBlock('from keyword import *', filename="/tmp/x.py")

      >>> print replace_star_imports(codeblock)
      [PYFLYBY] /tmp/x.py: replaced 'from keyword import *' with 2 imports
      from keyword import iskeyword, kwlist
      <BLANKLINE>

    Usually you'll want to remove unused imports after replacing star imports.

    @type codeblock:
      L{PythonBlock} or convertible (C{str})
    @rtype:
      L{PythonBlock}
    """
    from pyflyby._modules import ModuleHandle
    params = ImportFormatParams(params)
    codeblock = PythonBlock(codeblock)
    filename = codeblock.filename
    transformer = SourceToSourceFileImportsTransformation(codeblock)
    for block in transformer.import_blocks:
        # Iterate over the import statements in C{block.input}.  We do this
        # instead of using C{block.importset} because the latter doesn't
        # preserve the order of inputs.  The order is important for
        # determining what's shadowed.
        imports = [
            imp for s in block.input.statements
            for imp in ImportStatement(s).imports
        ]
        # Process "from ... import *" statements.
        new_imports = []
        for imp in imports:
            if imp.split.member_name != "*":
                new_imports.append(imp)
            elif imp.split.module_name.startswith("."):
                # The source contains e.g. "from .foo import *".  Right now we
                # don't have a good way to figure out the absolute module
                # name, so we can't get at foo.  That said, there's a decent
                # chance that this is inside an __init__ anyway, which is one
                # of the few justifiable use cases for star imports in library
                # code.
                logger.warning(
                    "%s: can't replace star imports in relative import: %s",
                    filename,
                    imp.pretty_print().strip())
                new_imports.append(imp)
            else:
                module = ModuleHandle(imp.split.module_name)
                try:
                    with ImportPathForRelativeImportsCtx(codeblock):
                        exports = module.exports
                except Exception as e:
                    logger.warning(
                        "%s: couldn't import '%s' to enumerate exports, "
                        "leaving unchanged: '%s'.  %s: %s", filename,
                        module.name, imp,
                        type(e).__name__, e)
                    new_imports.append(imp)
                    continue
                if not exports:
                    # We found nothing in the target module.  This probably
                    # means that module itself is just importing things from
                    # other modules.  Currently we intentionally exclude those
                    # imports since usually we don't want them.  TODO: do
                    # something better here.
                    logger.warning("%s: found nothing to import from %s, ",
                                   "leaving unchanged: '%s'", filename, module,
                                   imp)
                    new_imports.append(imp)
                else:
                    new_imports.extend(exports)
                    logger.info("%s: replaced %r with %d imports", filename,
                                imp.pretty_print().strip(), len(exports))
        block.importset = ImportSet(new_imports, ignore_shadowed=True)
    return transformer.output(params=params)
示例#11
0
    def _from_code(
            cls,
            blocks,
            _mandatory_imports_blocks_deprecated=(),
            _forget_imports_blocks_deprecated=(),
    ):
        """
        Load an import database from code.

          >>> ImportDB._from_code('''
          ...     import foo, bar as barf
          ...     from xx import yy
          ...     __mandatory_imports__ = ['__future__.division',
          ...                              'import aa . bb . cc as dd']
          ...     __forget_imports__ = ['xx.yy', 'from xx import zz']
          ...     __canonical_imports__ = {'bad.baad': 'good.goood'}
          ... ''')
          ImportDB('''
            import bar as barf
            import foo
          <BLANKLINE>
            __mandatory_imports__ = [
              'from __future__ import division',
              'from aa.bb import cc as dd',
            ]
          <BLANKLINE>
            __canonical_imports__ = {
              'bad.baad': 'good.goood',
            }
          <BLANKLINE>
            __forget_imports__ = [
              'from xx import yy',
              'from xx import zz',
            ]
          ''')

        @rtype:
          L{ImportDB}
        """
        if not isinstance(blocks, (tuple, list)):
            blocks = [blocks]
        if not isinstance(_mandatory_imports_blocks_deprecated, (tuple, list)):
            _mandatory_imports_blocks_deprecated = [
                _mandatory_imports_blocks_deprecated
            ]
        if not isinstance(_forget_imports_blocks_deprecated, (tuple, list)):
            _forget_imports_blocks_deprecated = [
                _forget_imports_blocks_deprecated
            ]
        known_imports = []
        mandatory_imports = []
        canonical_imports = []
        forget_imports = []
        blocks = [PythonBlock(b) for b in blocks]
        for block in blocks:
            for statement in block.statements:
                if statement.is_comment_or_blank:
                    continue
                if statement.is_import:
                    known_imports.extend(ImportStatement(statement).imports)
                    continue
                try:
                    name, value = statement.get_assignment_literal_value()
                    if name == "__mandatory_imports__":
                        mandatory_imports.append(cls._parse_import_set(value))
                    elif name == "__canonical_imports__":
                        canonical_imports.append(cls._parse_import_map(value))
                    elif name == "__forget_imports__":
                        forget_imports.append(cls._parse_import_set(value))
                    else:
                        raise ValueError(
                            "Unknown assignment to %r (expected one of "
                            "__mandatory_imports__, __canonical_imports__, "
                            "__forget_imports__)" % (name, ))
                except ValueError as e:
                    raise ValueError("While parsing %s: error in %r: %s" %
                                     (block.filename, statement, e))
        for block in _mandatory_imports_blocks_deprecated:
            mandatory_imports.append(ImportSet(block))
        for block in _forget_imports_blocks_deprecated:
            forget_imports.append(ImportSet(block))
        return cls._from_data(known_imports, mandatory_imports,
                              canonical_imports, forget_imports)
示例#12
0
def test_ImportStatement_flags_2():
    stmt = ImportStatement("from _future__ import division, print_function")
    assert stmt.flags == CompilerFlags.from_int(0)
示例#13
0
def test_ImportStatement_flags_1():
    stmt = ImportStatement("from __future__ import division, print_function")
    assert stmt.flags == CompilerFlags('division', 'print_function')
示例#14
0
def test_ImportStatement_relative_1():
    stmt = ImportStatement("from .foo import bar")
    assert stmt.fromname == ".foo"
    assert stmt.aliases == (("bar", None), )
    assert stmt.imports == (Import(ImportSplit(".foo", "bar", None)), )
    assert str(stmt) == "from .foo import bar"
示例#15
0
def test_ImportStatement_deep_member_1():
    stmt = ImportStatement("from foo.bar import baz")
    assert stmt.fromname == "foo.bar"
    assert stmt.aliases == (("baz", None), )
    assert stmt.imports == (Import(ImportSplit("foo.bar", "baz", None)), )
    assert str(stmt) == "from foo.bar import baz"
示例#16
0
def test_ImportStatement_1():
    stmt = ImportStatement("import  foo . bar")
    assert stmt.fromname == None
    assert stmt.aliases == (("foo.bar", None), )
    assert stmt.imports == (Import(ImportSplit(None, "foo.bar", None)), )
    assert str(stmt) == "import foo.bar"