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)
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"
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"
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)
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)
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)
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)
def test_ImportStatement_flags_2(): stmt = ImportStatement("from _future__ import division, print_function") assert stmt.flags == CompilerFlags.from_int(0)
def test_ImportStatement_flags_1(): stmt = ImportStatement("from __future__ import division, print_function") assert stmt.flags == CompilerFlags('division', 'print_function')
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"
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"
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"