From 186432da8d4da69730106f3dbeab8bef71fd68f5 Mon Sep 17 00:00:00 2001 From: dosisod <39638017+dosisod@users.noreply.github.com> Date: Mon, 24 Apr 2023 01:04:58 -0700 Subject: [PATCH] Replace `x[:]` with `x.copy()` (#14949) This PR fixes the [`FURB145`](https://github.com/dosisod/refurb/blob/master/docs/checks.md#furb145-no-slice-copy) error code from Refurb. In my (limited) testing, using `x.copy()` is faster then both the interpreted and compiled versions of `x[:]` (see https://github.com/python/mypy/pull/14887#discussion_r1134836243). See https://github.com/python/mypy/pull/14887 for more info. --- mypy/build.py | 2 +- mypy/checkexpr.py | 2 +- mypy/constraints.py | 2 +- mypy/dmypy_server.py | 4 ++-- mypy/errors.py | 4 ++-- mypy/memprofile.py | 2 +- mypy/mro.py | 2 +- mypy/semanal_main.py | 2 +- mypy/server/deps.py | 2 +- mypy/server/update.py | 6 +++--- mypy/strconv.py | 2 +- mypy/stubgenc.py | 2 +- mypy/test/helpers.py | 2 +- mypy/test/teststubtest.py | 4 ++-- mypy/treetransform.py | 14 +++++++------- mypyc/analysis/dataflow.py | 2 +- mypyc/ir/module_ir.py | 2 +- mypyc/ir/ops.py | 10 +++++----- mypyc/irbuild/expression.py | 4 ++-- mypyc/irbuild/ll_builder.py | 2 +- mypyc/irbuild/prepare.py | 2 +- mypyc/transform/refcount.py | 2 +- runtests.py | 2 +- 23 files changed, 39 insertions(+), 39 deletions(-) diff --git a/mypy/build.py b/mypy/build.py index b8e70b19b8cb..79846a1032b7 100644 --- a/mypy/build.py +++ b/mypy/build.py @@ -1911,7 +1911,7 @@ def __init__( self.caller_state = caller_state self.caller_line = caller_line if caller_state: - self.import_context = caller_state.import_context[:] + self.import_context = caller_state.import_context.copy() self.import_context.append((caller_state.xpath, caller_line)) else: self.import_context = [] diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 0a8dedb1342a..e7428f58ec85 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4472,7 +4472,7 @@ def infer_lambda_type_using_context( is_ellipsis_args=False, arg_types=[AnyType(TypeOfAny.special_form)] * len(arg_kinds), arg_kinds=arg_kinds, - arg_names=e.arg_names[:], + arg_names=e.arg_names.copy(), ) if ARG_STAR in arg_kinds or ARG_STAR2 in arg_kinds: diff --git a/mypy/constraints.py b/mypy/constraints.py index b145e5b8bd55..cafb95015a1d 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -1158,7 +1158,7 @@ def find_matching_overload_items( if not res: # Falling back to all items if we can't find a match is pretty arbitrary, but # it maintains backward compatibility. - res = items[:] + res = items.copy() return res diff --git a/mypy/dmypy_server.py b/mypy/dmypy_server.py index 48e46ac8ba84..1f038397f2ea 100644 --- a/mypy/dmypy_server.py +++ b/mypy/dmypy_server.py @@ -599,7 +599,7 @@ def fine_grained_increment_follow_imports(self, sources: list[BuildSource]) -> l messages = fine_grained_manager.update(changed, [], followed=True) # Follow deps from changed modules (still within graph). - worklist = changed[:] + worklist = changed.copy() while worklist: module = worklist.pop() if module[0] not in graph: @@ -706,7 +706,7 @@ def find_reachable_changed_modules( """ changed = [] new_files = [] - worklist = roots[:] + worklist = roots.copy() seen.update(source.module for source in worklist) while worklist: nxt = worklist.pop() diff --git a/mypy/errors.py b/mypy/errors.py index ab3d6d130339..09a905ccac54 100644 --- a/mypy/errors.py +++ b/mypy/errors.py @@ -338,11 +338,11 @@ def current_module(self) -> str | None: def import_context(self) -> list[tuple[str, int]]: """Return a copy of the import context.""" - return self.import_ctx[:] + return self.import_ctx.copy() def set_import_context(self, ctx: list[tuple[str, int]]) -> None: """Replace the entire import context with a new value.""" - self.import_ctx = ctx[:] + self.import_ctx = ctx.copy() def report( self, diff --git a/mypy/memprofile.py b/mypy/memprofile.py index 20e18c3c0bf2..48c0cb5ce022 100644 --- a/mypy/memprofile.py +++ b/mypy/memprofile.py @@ -103,7 +103,7 @@ def visit(o: object) -> None: objs.append(o) seen.add(id(o)) - for obj in objs[:]: + for obj in objs.copy(): if type(obj) is FakeInfo: # Processing these would cause a crash. continue diff --git a/mypy/mro.py b/mypy/mro.py index cc9f88a9d045..f34f3fa0c46d 100644 --- a/mypy/mro.py +++ b/mypy/mro.py @@ -44,7 +44,7 @@ def linearize_hierarchy( def merge(seqs: list[list[TypeInfo]]) -> list[TypeInfo]: - seqs = [s[:] for s in seqs] + seqs = [s.copy() for s in seqs] result: list[TypeInfo] = [] while True: seqs = [s for s in seqs if s] diff --git a/mypy/semanal_main.py b/mypy/semanal_main.py index 912851520958..d7e9712fa427 100644 --- a/mypy/semanal_main.py +++ b/mypy/semanal_main.py @@ -190,7 +190,7 @@ def process_top_levels(graph: Graph, scc: list[str], patches: Patches) -> None: # Initially all namespaces in the SCC are incomplete (well they are empty). state.manager.incomplete_namespaces.update(scc) - worklist = scc[:] + worklist = scc.copy() # HACK: process core stuff first. This is mostly needed to support defining # named tuples in builtin SCC. if all(m in worklist for m in core_modules): diff --git a/mypy/server/deps.py b/mypy/server/deps.py index 50b66b70b8aa..2659f942817d 100644 --- a/mypy/server/deps.py +++ b/mypy/server/deps.py @@ -1027,7 +1027,7 @@ def visit_tuple_type(self, typ: TupleType) -> list[str]: def visit_type_type(self, typ: TypeType) -> list[str]: triggers = self.get_type_triggers(typ.item) if not self.use_logical_deps: - old_triggers = triggers[:] + old_triggers = triggers.copy() for trigger in old_triggers: triggers.append(trigger.rstrip(">") + ".__init__>") triggers.append(trigger.rstrip(">") + ".__new__>") diff --git a/mypy/server/update.py b/mypy/server/update.py index e909840d2757..70c1a2df0195 100644 --- a/mypy/server/update.py +++ b/mypy/server/update.py @@ -187,7 +187,7 @@ def __init__(self, result: BuildResult) -> None: # Merge in any root dependencies that may not have been loaded merge_dependencies(manager.load_fine_grained_deps(FAKE_ROOT_MODULE), self.deps) self.previous_targets_with_errors = manager.errors.targets() - self.previous_messages: list[str] = result.errors[:] + self.previous_messages: list[str] = result.errors.copy() # Module, if any, that had blocking errors in the last run as (id, path) tuple. self.blocking_error: tuple[str, str] | None = None # Module that we haven't processed yet but that are known to be stale. @@ -302,7 +302,7 @@ def update( break messages = sort_messages_preserving_file_order(messages, self.previous_messages) - self.previous_messages = messages[:] + self.previous_messages = messages.copy() return messages def trigger(self, target: str) -> list[str]: @@ -322,7 +322,7 @@ def trigger(self, target: str) -> list[str]: ) # Preserve state needed for the next update. self.previous_targets_with_errors = self.manager.errors.targets() - self.previous_messages = self.manager.errors.new_messages()[:] + self.previous_messages = self.manager.errors.new_messages().copy() return self.update(changed_modules, []) def flush_cache(self) -> None: diff --git a/mypy/strconv.py b/mypy/strconv.py index e24be7fe35ca..c428addd43aa 100644 --- a/mypy/strconv.py +++ b/mypy/strconv.py @@ -154,7 +154,7 @@ def visit_func_def(self, o: mypy.nodes.FuncDef) -> str: return self.dump(a, o) def visit_overloaded_func_def(self, o: mypy.nodes.OverloadedFuncDef) -> str: - a: Any = o.items[:] + a: Any = o.items.copy() if o.type: a.insert(0, o.type) if o.impl: diff --git a/mypy/stubgenc.py b/mypy/stubgenc.py index da0fc5cee6b9..4fc9f8c6fdfa 100755 --- a/mypy/stubgenc.py +++ b/mypy/stubgenc.py @@ -254,7 +254,7 @@ def add_typing_import(output: list[str]) -> list[str]: if names: return [f"from typing import {', '.join(names)}", ""] + output else: - return output[:] + return output.copy() def get_members(obj: object) -> list[tuple[str, Any]]: diff --git a/mypy/test/helpers.py b/mypy/test/helpers.py index 52b2497f0c3c..cf3dd74375ee 100644 --- a/mypy/test/helpers.py +++ b/mypy/test/helpers.py @@ -256,7 +256,7 @@ def local_sys_path_set() -> Iterator[None]: This can be used by test cases that do runtime imports, for example by the stubgen tests. """ - old_sys_path = sys.path[:] + old_sys_path = sys.path.copy() if not ("" in sys.path or "." in sys.path): sys.path.insert(0, "") try: diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index c30864c6cc28..94db9f55aa20 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -19,7 +19,7 @@ @contextlib.contextmanager def use_tmp_dir(mod_name: str) -> Iterator[str]: current = os.getcwd() - current_syspath = sys.path[:] + current_syspath = sys.path.copy() with tempfile.TemporaryDirectory() as tmp: try: os.chdir(tmp) @@ -27,7 +27,7 @@ def use_tmp_dir(mod_name: str) -> Iterator[str]: sys.path.insert(0, tmp) yield tmp finally: - sys.path = current_syspath[:] + sys.path = current_syspath.copy() if mod_name in sys.modules: del sys.modules[mod_name] diff --git a/mypy/treetransform.py b/mypy/treetransform.py index 535f50d5cf5e..25ed11d67982 100644 --- a/mypy/treetransform.py +++ b/mypy/treetransform.py @@ -145,7 +145,7 @@ def __init__(self) -> None: def visit_mypy_file(self, node: MypyFile) -> MypyFile: assert self.test_only, "This visitor should not be used for whole files." # NOTE: The 'names' and 'imports' instance variables will be empty! - ignored_lines = {line: codes[:] for line, codes in node.ignored_lines.items()} + ignored_lines = {line: codes.copy() for line, codes in node.ignored_lines.items()} new = MypyFile(self.statements(node.defs), [], node.is_bom, ignored_lines=ignored_lines) new._fullname = node._fullname new.path = node.path @@ -153,10 +153,10 @@ def visit_mypy_file(self, node: MypyFile) -> MypyFile: return new def visit_import(self, node: Import) -> Import: - return Import(node.ids[:]) + return Import(node.ids.copy()) def visit_import_from(self, node: ImportFrom) -> ImportFrom: - return ImportFrom(node.id, node.relative, node.names[:]) + return ImportFrom(node.id, node.relative, node.names.copy()) def visit_import_all(self, node: ImportAll) -> ImportAll: return ImportAll(node.id, node.relative) @@ -267,10 +267,10 @@ def visit_class_def(self, node: ClassDef) -> ClassDef: return new def visit_global_decl(self, node: GlobalDecl) -> GlobalDecl: - return GlobalDecl(node.names[:]) + return GlobalDecl(node.names.copy()) def visit_nonlocal_decl(self, node: NonlocalDecl) -> NonlocalDecl: - return NonlocalDecl(node.names[:]) + return NonlocalDecl(node.names.copy()) def visit_block(self, node: Block) -> Block: return Block(self.statements(node.body)) @@ -513,8 +513,8 @@ def visit_call_expr(self, node: CallExpr) -> CallExpr: return CallExpr( self.expr(node.callee), self.expressions(node.args), - node.arg_kinds[:], - node.arg_names[:], + node.arg_kinds.copy(), + node.arg_names.copy(), self.optional_expr(node.analyzed), ) diff --git a/mypyc/analysis/dataflow.py b/mypyc/analysis/dataflow.py index 5136dc9f9abb..ee2ff06b0f03 100644 --- a/mypyc/analysis/dataflow.py +++ b/mypyc/analysis/dataflow.py @@ -145,7 +145,7 @@ def cleanup_cfg(blocks: list[BasicBlock]) -> None: # Then delete any blocks that have no predecessors changed = False cfg = get_cfg(blocks) - orig_blocks = blocks[:] + orig_blocks = blocks.copy() blocks.clear() for i, block in enumerate(orig_blocks): if i == 0 or cfg.pred[block]: diff --git a/mypyc/ir/module_ir.py b/mypyc/ir/module_ir.py index 4b6a177af149..dcf6f8768547 100644 --- a/mypyc/ir/module_ir.py +++ b/mypyc/ir/module_ir.py @@ -23,7 +23,7 @@ def __init__( final_names: list[tuple[str, RType]], ) -> None: self.fullname = fullname - self.imports = imports[:] + self.imports = imports.copy() self.functions = functions self.classes = classes self.final_names = final_names diff --git a/mypyc/ir/ops.py b/mypyc/ir/ops.py index 0ab25aec8e8c..229bdfb4a326 100644 --- a/mypyc/ir/ops.py +++ b/mypyc/ir/ops.py @@ -299,7 +299,7 @@ def __init__(self, dest: Register, src: list[Value], line: int = -1) -> None: self.src = src def sources(self) -> list[Value]: - return self.src[:] + return self.src.copy() def stolen(self) -> list[Value]: return [] @@ -542,7 +542,7 @@ def __init__(self, fn: FuncDecl, args: Sequence[Value], line: int) -> None: super().__init__(line) def sources(self) -> list[Value]: - return list(self.args[:]) + return list(self.args.copy()) def accept(self, visitor: OpVisitor[T]) -> T: return visitor.visit_call(self) @@ -570,7 +570,7 @@ def __init__(self, obj: Value, method: str, args: list[Value], line: int = -1) - super().__init__(line) def sources(self) -> list[Value]: - return self.args[:] + [self.obj] + return self.args.copy() + [self.obj] def accept(self, visitor: OpVisitor[T]) -> T: return visitor.visit_method_call(self) @@ -790,7 +790,7 @@ def __init__(self, items: list[Value], line: int) -> None: self.type = self.tuple_type def sources(self) -> list[Value]: - return self.items[:] + return self.items.copy() def accept(self, visitor: OpVisitor[T]) -> T: return visitor.visit_tuple_set(self) @@ -1394,7 +1394,7 @@ def __init__(self, src: list[Value]) -> None: self.src = src def sources(self) -> list[Value]: - return self.src[:] + return self.src.copy() def accept(self, visitor: OpVisitor[T]) -> T: return visitor.visit_keep_alive(self) diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index d94bd228e948..a98ddfdceecc 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -385,7 +385,7 @@ def translate_method_call(builder: IRBuilder, expr: CallExpr, callee: MemberExpr def call_classmethod(builder: IRBuilder, ir: ClassIR, expr: CallExpr, callee: MemberExpr) -> Value: decl = ir.method_decl(callee.name) args = [] - arg_kinds, arg_names = expr.arg_kinds[:], expr.arg_names[:] + arg_kinds, arg_names = expr.arg_kinds.copy(), expr.arg_names.copy() # Add the class argument for class methods in extension classes if decl.kind == FUNC_CLASSMETHOD and ir.is_ext_class: args.append(builder.load_native_type_object(ir.fullname)) @@ -452,7 +452,7 @@ def translate_super_method_call(builder: IRBuilder, expr: CallExpr, callee: Supe decl = base.method_decl(callee.name) arg_values = [builder.accept(arg) for arg in expr.args] - arg_kinds, arg_names = expr.arg_kinds[:], expr.arg_names[:] + arg_kinds, arg_names = expr.arg_kinds.copy(), expr.arg_names.copy() if decl.kind != FUNC_STATICMETHOD: # Grab first argument diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py index 116898504ebe..d60ba917dae7 100644 --- a/mypyc/irbuild/ll_builder.py +++ b/mypyc/irbuild/ll_builder.py @@ -266,7 +266,7 @@ def self(self) -> Register: def flush_keep_alives(self) -> None: if self.keep_alives: - self.add(KeepAlive(self.keep_alives[:])) + self.add(KeepAlive(self.keep_alives.copy())) self.keep_alives = [] # Type conversions diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index e82e9fd3ff76..5e6520048197 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -85,7 +85,7 @@ def build_type_map( ) class_ir.is_ext_class = is_extension_class(cdef) if class_ir.is_ext_class: - class_ir.deletable = cdef.info.deletable_attributes[:] + class_ir.deletable = cdef.info.deletable_attributes.copy() # If global optimizations are disabled, turn of tracking of class children if not options.global_opts: class_ir.children = None diff --git a/mypyc/transform/refcount.py b/mypyc/transform/refcount.py index 13f6a121e7f1..f2ab438f6576 100644 --- a/mypyc/transform/refcount.py +++ b/mypyc/transform/refcount.py @@ -70,7 +70,7 @@ def insert_ref_count_opcodes(ir: FuncIR) -> None: defined = analyze_must_defined_regs(ir.blocks, cfg, args, values, strict_errors=True) ordering = make_value_ordering(ir) cache: BlockCache = {} - for block in ir.blocks[:]: + for block in ir.blocks.copy(): if isinstance(block.ops[-1], (Branch, Goto)): insert_branch_inc_and_decrefs( block, diff --git a/runtests.py b/runtests.py index ade0a8adee5e..f99fe5dc8b16 100755 --- a/runtests.py +++ b/runtests.py @@ -129,7 +129,7 @@ def main() -> None: exit(1) if not args: - args = DEFAULT_COMMANDS[:] + args = DEFAULT_COMMANDS.copy() status = 0