def remove_duplicated_imports(partitions): seen = set() seen_module_names = set() without_exact_duplicates = [] for partition in partitions: if partition.code_type is CodeType.IMPORT: import_obj = import_obj_from_str(partition.src) if import_obj not in seen: seen.add(import_obj) if (isinstance(import_obj, ImportImport) and not import_obj.import_statement.asname): seen_module_names.update( _module_to_base_modules( import_obj.import_statement.module, ), ) without_exact_duplicates.append(partition) else: without_exact_duplicates.append(partition) partitions = [] for partition in without_exact_duplicates: if partition.code_type is CodeType.IMPORT: import_obj = import_obj_from_str(partition.src) if (isinstance(import_obj, ImportImport) and not import_obj.import_statement.asname and import_obj.import_statement.module in seen_module_names): continue partitions.append(partition) return partitions
def _validate_import(s: str) -> str: try: import_obj_from_str(s) except (SyntaxError, KeyError): raise argparse.ArgumentTypeError(f'expected import: {s!r}') else: return s
def remove_duplicated_imports(partitions): # type: (Iterable[CodePartition]) -> List[CodePartition] seen = set() # type: Set[AbstractImportObj] seen_module_names = set() # type: Set[str] without_exact_duplicates = [] for partition in partitions: if partition.code_type is CodeType.IMPORT: import_obj = import_obj_from_str(partition.src) if import_obj not in seen: seen.add(import_obj) if (isinstance(import_obj, ImportImport) and not import_obj.import_statement.asname): seen_module_names.update( _module_to_base_modules( import_obj.import_statement.module, ), ) without_exact_duplicates.append(partition) else: without_exact_duplicates.append(partition) out_partitions = [] for partition in without_exact_duplicates: if partition.code_type is CodeType.IMPORT: import_obj = import_obj_from_str(partition.src) if (isinstance(import_obj, ImportImport) and not import_obj.import_statement.asname and import_obj.import_statement.module in seen_module_names): continue out_partitions.append(partition) return out_partitions
def _validate_import(s): try: import_obj_from_str(s) except (SyntaxError, KeyError): raise argparse.ArgumentTypeError('expected import: {!r}'.format(s)) else: return s
def _inner(): # type: () -> Generator[CodePartition, None, None] for partition in partitions: if (partition.code_type is not CodeType.IMPORT or import_obj_from_str( partition.src) not in to_remove_imports): yield partition
def _inner(): for partition in partitions: if partition.code_type is CodeType.IMPORT: import_obj = import_obj_from_str(partition.src) # cannot rewrite import-imports: makes undefined names if isinstance(import_obj, ImportImport): yield partition continue mod_parts = import_obj.import_statement.module.split('.') symbol = import_obj.import_statement.symbol asname = import_obj.import_statement.asname for orig_mod, new_mod, attr in to_replace: if ((attr == symbol and mod_parts == orig_mod) or (not attr and _mod_startswith(mod_parts, orig_mod))): mod_parts[:len(orig_mod)] = new_mod import_obj.ast_obj.module = '.'.join(mod_parts) new_src = import_obj.to_text() yield partition._replace(src=new_src) break # from x.y import z => import z elif (not attr and mod_parts + [symbol] == orig_mod and len(new_mod) == 1): mod_name, = new_mod asname_src = ' as {}'.format(asname) if asname else '' new_src = 'import {}{}\n'.format(mod_name, asname_src) yield partition._replace(src=new_src) break else: yield partition else: yield partition
def _inner(): for partition in partitions: if ( partition.code_type is not CodeType.IMPORT or import_obj_from_str(partition.src) not in to_remove_imports ): yield partition
def _inner(): seen = set() for partition in partitions: if partition.code_type is CodeType.IMPORT: import_obj = import_obj_from_str(partition.src) if import_obj not in seen: seen.add(import_obj) yield partition else: yield partition
def remove_imports(partitions, to_remove=()): to_remove_imports = set( import_obj_from_str(imp_statement) for imp_statement in to_remove) def _inner(): for partition in partitions: if (partition.code_type is not CodeType.IMPORT or import_obj_from_str( partition.src) not in to_remove_imports): yield partition return list(_inner())
def _inner(): for partition in partitions: if partition.code_type is CodeType.IMPORT: import_obj = import_obj_from_str(partition.src) if import_obj.has_multiple_imports: for new_import_obj in import_obj.split_imports(): yield CodePartition(CodeType.IMPORT, new_import_obj.to_text()) else: yield partition else: yield partition
def _inner(): for partition in partitions: if partition.code_type is CodeType.IMPORT: import_obj = import_obj_from_str(partition.src) if import_obj.has_multiple_imports: for new_import_obj in import_obj.split_imports(): yield CodePartition( CodeType.IMPORT, new_import_obj.to_text() ) else: yield partition else: yield partition
def remove_imports(partitions, to_remove=()): to_remove_imports = set() for s in to_remove: to_remove_imports.update(import_obj_from_str(s).split_imports()) def _inner(): for partition in partitions: if (partition.code_type is not CodeType.IMPORT or import_obj_from_str( partition.src) not in to_remove_imports): yield partition return list(_inner())
def remove_imports(partitions, to_remove=()): to_remove_imports = set( import_obj_from_str(imp_statement) for imp_statement in to_remove ) def _inner(): for partition in partitions: if ( partition.code_type is not CodeType.IMPORT or import_obj_from_str(partition.src) not in to_remove_imports ): yield partition return list(_inner())
def apply_import_sorting(partitions, **sort_kwargs): pre_import_code = [] imports = [] trash = [] rest = [] for partition in partitions: { CodeType.PRE_IMPORT_CODE: pre_import_code, CodeType.IMPORT: imports, CodeType.NON_CODE: trash, CodeType.CODE: rest, }[partition.code_type].append(partition) # Need to give an import a newline if it doesn't have one (needed for no # EOL) imports = [ partition if partition.src.endswith('\n') else CodePartition(CodeType.IMPORT, partition.src + '\n') for partition in imports ] import_obj_to_partition = dict( (import_obj_from_str(partition.src), partition) for partition in imports ) new_imports = [] sorted_blocks = sort(import_obj_to_partition.keys(), **sort_kwargs) for block in sorted_blocks: for import_obj in block: new_imports.append(import_obj_to_partition[import_obj]) new_imports.append(CodePartition(CodeType.NON_CODE, '\n')) # XXX: I want something like [x].join(...) (like str join) but for now # this works if new_imports: new_imports.pop() # There's the potential that we moved a bunch of whitespace onto the # beginning of the rest of the code. To fix this, we're going to combine # all of that code, and then make sure there are two linebreaks to start restsrc = _partitions_to_src(rest) restsrc = restsrc.rstrip() if restsrc: rest = [ CodePartition(CodeType.CODE, restsrc + '\n'), ] else: rest = [] return pre_import_code + new_imports + rest
def remove_imports(partitions, to_remove=()): # type: (Iterable[CodePartition], Tuple[str, ...]) -> List[CodePartition] to_remove_imports = set() # type: Set[AbstractImportObj] for s in to_remove: to_remove_imports.update(import_obj_from_str(s).split_imports()) def _inner(): # type: () -> Generator[CodePartition, None, None] for partition in partitions: if (partition.code_type is not CodeType.IMPORT or import_obj_from_str( partition.src) not in to_remove_imports): yield partition return list(_inner())
def apply_import_sorting(partitions, **sort_kwargs): pre_import_code = [] imports = [] trash = [] rest = [] for partition in partitions: { CodeType.PRE_IMPORT_CODE: pre_import_code, CodeType.IMPORT: imports, CodeType.NON_CODE: trash, CodeType.CODE: rest, }[partition.code_type].append(partition) # Need to give an import a newline if it doesn't have one (needed for no # EOL) imports = [ partition if partition.src.endswith('\n') else CodePartition( CodeType.IMPORT, partition.src + '\n') for partition in imports ] import_obj_to_partition = dict( (import_obj_from_str(partition.src), partition) for partition in imports) new_imports = [] sorted_blocks = sort(import_obj_to_partition.keys(), **sort_kwargs) for block in sorted_blocks: for import_obj in block: new_imports.append(import_obj_to_partition[import_obj]) new_imports.append(CodePartition(CodeType.NON_CODE, '\n')) # XXX: I want something like [x].join(...) (like str join) but for now # this works if new_imports: new_imports.pop() # There's the potential that we moved a bunch of whitespace onto the # beginning of the rest of the code. To fix this, we're going to combine # all of that code, and then make sure there are two linebreaks to start restsrc = _partitions_to_src(rest) restsrc = restsrc.rstrip() if restsrc: rest = [ CodePartition(CodeType.CODE, restsrc + '\n'), ] else: rest = [] return pre_import_code + new_imports + rest
def apply_import_sorting( partitions, separate_relative=False, separate_from_import=False, **sort_kwargs ): pre_import_code = [] imports = [] trash = [] rest = [] for partition in partitions: { CodeType.PRE_IMPORT_CODE: pre_import_code, CodeType.IMPORT: imports, CodeType.NON_CODE: trash, CodeType.CODE: rest, }[partition.code_type].append(partition) # Need to give an import a newline if it doesn't have one (needed for no # EOL) imports = [ partition if partition.src.endswith('\n') else CodePartition(CodeType.IMPORT, partition.src + '\n') for partition in imports ] import_obj_to_partition = dict( (import_obj_from_str(partition.src), partition) for partition in imports ) new_imports = [] relative_imports = [] def _import_type_switches(last_import_obj, import_obj): """Returns True if separate_from_import is True and `import_obj` is :class:`aspy.refactor_imports.import_obj.FromImport` and ``last_import_obj`` is :class:`aspy.refactor_imports.import_obj.ImportImport` """ return ( separate_from_import and last_import_obj is not None and type(last_import_obj) is not type(import_obj) ) sorted_blocks = sort(import_obj_to_partition.keys(), **sort_kwargs) for block in sorted_blocks: last_import_obj = None for import_obj in block: if separate_relative and import_obj.is_explicit_relative: relative_imports.append(import_obj_to_partition[import_obj]) else: if _import_type_switches(last_import_obj, import_obj): new_imports.append(CodePartition(CodeType.NON_CODE, '\n')) last_import_obj = import_obj new_imports.append(import_obj_to_partition[import_obj]) # There's an edge case if both --separate-relative and # --separate-from-import are passed where the first-party imports # will *all* be explicit relative imports and sorted into the special # block. In this case, we don't want the first-party block to just # be a single newline. See #23 if last_import_obj is not None: new_imports.append(CodePartition(CodeType.NON_CODE, '\n')) if relative_imports: relative_imports.insert(0, CodePartition(CodeType.NON_CODE, '\n')) # XXX: I want something like [x].join(...) (like str join) but for now # this works if new_imports: new_imports.pop() # There's the potential that we moved a bunch of whitespace onto the # beginning of the rest of the code. To fix this, we're going to combine # all of that code, and then make sure there are two linebreaks to start restsrc = _partitions_to_src(rest) restsrc = restsrc.rstrip() if restsrc: rest = [ CodePartition(CodeType.CODE, restsrc + '\n'), ] else: rest = [] return pre_import_code + new_imports + relative_imports + rest
def apply_import_sorting(partitions, separate_relative=False, separate_from_import=False, **sort_kwargs): pre_import_code = [] imports = [] trash = [] rest = [] for partition in partitions: { CodeType.PRE_IMPORT_CODE: pre_import_code, CodeType.IMPORT: imports, CodeType.NON_CODE: trash, CodeType.CODE: rest, }[partition.code_type].append(partition) # Need to give an import a newline if it doesn't have one (needed for no # EOL) imports = [ partition if partition.src.endswith('\n') else CodePartition( CodeType.IMPORT, partition.src + '\n') for partition in imports ] import_obj_to_partition = { import_obj_from_str(partition.src): partition for partition in imports } new_imports = [] relative_imports = [] def _import_type_switches(last_import_obj, import_obj): """Returns True if separate_from_import is True and `import_obj` is :class:`aspy.refactor_imports.import_obj.FromImport` and ``last_import_obj`` is :class:`aspy.refactor_imports.import_obj.ImportImport` """ return (separate_from_import and last_import_obj is not None and type(last_import_obj) is not type(import_obj)) sorted_blocks = sort(import_obj_to_partition.keys(), **sort_kwargs) for block in sorted_blocks: last_import_obj = None for import_obj in block: if separate_relative and import_obj.is_explicit_relative: relative_imports.append(import_obj_to_partition[import_obj]) else: if _import_type_switches(last_import_obj, import_obj): new_imports.append(CodePartition(CodeType.NON_CODE, '\n')) last_import_obj = import_obj new_imports.append(import_obj_to_partition[import_obj]) # There's an edge case if both --separate-relative and # --separate-from-import are passed where the first-party imports # will *all* be explicit relative imports and sorted into the special # block. In this case, we don't want the first-party block to just # be a single newline. See #23 if last_import_obj is not None: new_imports.append(CodePartition(CodeType.NON_CODE, '\n')) if relative_imports: relative_imports.insert(0, CodePartition(CodeType.NON_CODE, '\n')) # XXX: I want something like [x].join(...) (like str join) but for now # this works if new_imports: new_imports.pop() # There's the potential that we moved a bunch of whitespace onto the # beginning of the rest of the code. To fix this, we're going to combine # all of that code, and then make sure there are two linebreaks to start restsrc = _partitions_to_src(rest) restsrc = restsrc.rstrip() if restsrc: rest = [CodePartition(CodeType.CODE, restsrc + '\n')] else: rest = [] return pre_import_code + new_imports + relative_imports + rest
def test_import_obj_from_str(input_str, expected): assert import_obj_from_str(input_str) == expected
def test_is_explicit_relative(input_str, expected): assert import_obj_from_str(input_str).is_explicit_relative is expected
def _inner(): for partition in partitions: if (partition.code_type is not CodeType.IMPORT or import_obj_from_str( partition.src) not in to_remove_imports): yield partition