diff --git a/.pylintrc b/.pylintrc index c6c315de6..b250311f7 100644 --- a/.pylintrc +++ b/.pylintrc @@ -60,6 +60,7 @@ disable= modified-iterating-list, used-before-assignment, unsubscriptable-object, + use-sequence-for-iteration, unpacking-non-sequence, # Rope: to be removed. @@ -70,8 +71,6 @@ disable= superfluous-parens, unused-import, unused-wildcard-import, - useless-super-delegation, - useless-else-on-loop, #Else clause on loop without a break statement, remove the else and de-indent all the code inside it. unidiomatic-typecheck, wildcard-import, @@ -93,7 +92,11 @@ disable= super-init-not-called, unnecessary-lambda, unsupported-assignment-operation, - + + # Rope: recently enabled checks. + + # useless-super-delegation, + # Leo: Standard suppressions. arguments-renamed, # cursesGui2.py diff --git a/rope/base/arguments.py b/rope/base/arguments.py index 12a626816..b92f5cdde 100644 --- a/rope/base/arguments.py +++ b/rope/base/arguments.py @@ -1,5 +1,6 @@ -import rope.base.evaluate -from rope.base import ast +import ast + +from rope.base import builtins, evaluate, pyobjects class Arguments: @@ -36,9 +37,10 @@ def get_pynames(self, parameters): def get_instance_pyname(self): if self.args: return self._evaluate(self.args[0]) + return None def _evaluate(self, ast_node): - return rope.base.evaluate.eval_node(self.scope, ast_node) + return evaluate.eval_node(self.scope, ast_node) def create_arguments(primary, pyfunction, call_node, scope): @@ -99,13 +101,13 @@ def _is_method_call(primary, pyfunction): return False pyobject = primary.get_object() if ( - isinstance(pyobject.get_type(), rope.base.pyobjects.PyClass) - and isinstance(pyfunction, rope.base.pyobjects.PyFunction) - and isinstance(pyfunction.parent, rope.base.pyobjects.PyClass) + isinstance(pyobject.get_type(), pyobjects.PyClass) + and isinstance(pyfunction, pyobjects.PyFunction) + and isinstance(pyfunction.parent, pyobjects.PyClass) ): return True - if isinstance( - pyobject.get_type(), rope.base.pyobjects.AbstractClass - ) and isinstance(pyfunction, rope.base.builtins.BuiltinFunction): + if isinstance(pyobject.get_type(), pyobjects.AbstractClass) and isinstance( + pyfunction, builtins.BuiltinFunction + ): return True return False diff --git a/rope/base/ast.py b/rope/base/ast.py index f64a5b3f1..c7add2502 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -4,24 +4,6 @@ from rope.base import fscommands -def parse(source, filename=""): - # NOTE: the raw string should be given to `compile` function - if isinstance(source, str): - source = fscommands.unicode_to_file_data(source) - if b"\r" in source: - source = source.replace(b"\r\n", b"\n").replace(b"\r", b"\n") - if not source.endswith(b"\n"): - source += b"\n" - try: - return ast.parse(source, filename="") - except (TypeError, ValueError) as e: - error = SyntaxError() - error.lineno = 1 - error.filename = filename - error.msg = str(e) - raise error - - def call_for_nodes(node, callback, recursive=False): """If callback returns `True` the child nodes are skipped""" result = callback(node) diff --git a/rope/base/astwrapper.py b/rope/base/astwrapper.py new file mode 100644 index 000000000..950e5fd7d --- /dev/null +++ b/rope/base/astwrapper.py @@ -0,0 +1,33 @@ +"""Wrappers for stdlib.ast.parse and stdlib.ast.walk.""" +import ast + +from rope.base import astutils, fscommands + + +def parse(source, filename=""): + # NOTE: the raw string should be given to `compile` function + if isinstance(source, str): + source = fscommands.unicode_to_file_data(source) + if b"\r" in source: + source = source.replace(b"\r\n", b"\n").replace(b"\r", b"\n") + if not source.endswith(b"\n"): + source += b"\n" + try: + return ast.parse(source, filename="") + except (TypeError, ValueError) as e: + error = SyntaxError() + error.lineno = 1 + error.filename = filename + error.msg = str(e) + raise error + + +def walk(node, walker) -> None: + """Walk the syntax tree""" + method_name = "_" + node.__class__.__name__ + method = getattr(walker, method_name, None) + if method is not None: + method(node) + return + for child in astutils.get_child_nodes(node): + walk(child, walker) diff --git a/rope/base/builtins.py b/rope/base/builtins.py index 9982b69ec..497463d20 100644 --- a/rope/base/builtins.py +++ b/rope/base/builtins.py @@ -1,9 +1,10 @@ """This module tries to support builtin types and functions.""" +import ast import inspect import io import rope.base.evaluate -from rope.base import ast, pynames, pyobjects, arguments, utils +from rope.base import arguments, pynames, pyobjects, utils try: @@ -39,7 +40,7 @@ def attributes(self): if self.pycore is not None: submodules = self.pycore._builtin_submodules(self.name) for name, module in submodules.items(): - result[name] = rope.base.builtins.BuiltinName(module) + result[name] = BuiltinName(module) return result @property diff --git a/rope/base/libutils.py b/rope/base/libutils.py index 4c966ccae..c2c1d3f77 100644 --- a/rope/base/libutils.py +++ b/rope/base/libutils.py @@ -3,9 +3,7 @@ import rope.base.project import rope.base.pycore -from rope.base import pyobjectsdef -from rope.base import utils -from rope.base import taskhandle +from rope.base import pyobjectsdef, taskhandle, utils def path_to_resource(project, path, type=None): diff --git a/rope/base/oi/soi.py b/rope/base/oi/soi.py index 2cecdf8b1..4886864bd 100644 --- a/rope/base/oi/soi.py +++ b/rope/base/oi/soi.py @@ -7,7 +7,7 @@ import rope.base.builtins import rope.base.pynames import rope.base.pyobjects -from rope.base import evaluate, utils, arguments +from rope.base import arguments, evaluate, utils from rope.base.oi.type_hinting.factory import get_type_hinting_factory diff --git a/rope/base/pycore.py b/rope/base/pycore.py index 7428bc1ee..abab0120e 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -8,13 +8,14 @@ import rope.base.oi.doa import rope.base.oi.objectinfo import rope.base.oi.soa -from rope.base import builtins -from rope.base import exceptions -from rope.base import pyobjectsdef -from rope.base import stdmods -from rope.base import taskhandle -from rope.base import utils -from rope.base.exceptions import ModuleNotFoundError +from rope.base import ( + builtins, + exceptions, + pyobjectsdef, + stdmods, + taskhandle, + utils, +) class PyCore: diff --git a/rope/base/pynames.py b/rope/base/pynames.py index eaac2ce98..e466d07aa 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -1,3 +1,4 @@ +# These imports are tricky. It's easy to cause circular imports. from __future__ import annotations import typing @@ -7,6 +8,7 @@ if typing.TYPE_CHECKING: + # pyobjectsdef appears only in annotations. from typing import Union from rope.base import pyobjectsdef diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 92e9e78c6..2bbbf4d2b 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -5,13 +5,14 @@ import rope.base.oi.soi import rope.base.pyscopes from rope.base import ( - pynamesdef, - exceptions, + arguments, ast, + astwrapper, astutils, - pyobjects, + exceptions, fscommands, - arguments, + pynamesdef, + pyobjects, utils, ) @@ -197,7 +198,7 @@ def _init_source(self, pycore, source_code, resource): source_bytes = fscommands.unicode_to_file_data(source_code) else: source_bytes = source_code - ast_node = ast.parse(source_bytes, filename=filename) + ast_node = astwrapper.parse(source_bytes, filename=filename) except SyntaxError as e: raise exceptions.ModuleSyntaxError(filename, e.lineno, e.msg) except UnicodeDecodeError as e: diff --git a/rope/base/resources.py b/rope/base/resources.py index 4a518ed75..31204a48c 100644 --- a/rope/base/resources.py +++ b/rope/base/resources.py @@ -30,9 +30,7 @@ import re import warnings -from rope.base import change -from rope.base import exceptions -from rope.base import fscommands +from rope.base import change, exceptions, fscommands from pathlib import Path diff --git a/rope/base/taskhandle.py b/rope/base/taskhandle.py index 8c49ec947..afcb97ed0 100644 --- a/rope/base/taskhandle.py +++ b/rope/base/taskhandle.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod from typing import Optional, Sequence -from rope.base import utils, exceptions +from rope.base import exceptions, utils class BaseJobSet(ABC): diff --git a/rope/contrib/autoimport/parse.py b/rope/contrib/autoimport/parse.py index 1e4cb6bde..b4ad6d2f5 100644 --- a/rope/contrib/autoimport/parse.py +++ b/rope/contrib/autoimport/parse.py @@ -3,7 +3,7 @@ Can extract names from source code of a python file, .so object, or builtin module. """ - +import ast import inspect import logging import pathlib @@ -20,8 +20,6 @@ PartialName, Source, ) -from rope.base import ast - logger = logging.getLogger(__name__) diff --git a/rope/contrib/autoimport/pickle.py b/rope/contrib/autoimport/pickle.py index 893900e35..ef733947a 100644 --- a/rope/contrib/autoimport/pickle.py +++ b/rope/contrib/autoimport/pickle.py @@ -12,14 +12,16 @@ import re -from rope.base import builtins -from rope.base import exceptions -from rope.base import libutils -from rope.base import pynames -from rope.base import pyobjects -from rope.base import resources -from rope.base import resourceobserver -from rope.base import taskhandle +from rope.base import ( + builtins, + exceptions, + libutils, + pynames, + pyobjects, + resourceobserver, + resources, + taskhandle, +) from rope.refactor import importutils diff --git a/rope/contrib/autoimport/sqlite.py b/rope/contrib/autoimport/sqlite.py index f778eac0b..381aa99e0 100644 --- a/rope/contrib/autoimport/sqlite.py +++ b/rope/contrib/autoimport/sqlite.py @@ -8,7 +8,12 @@ from pathlib import Path from typing import Generator, Iterable, List, Optional, Set, Tuple, Iterator -from rope.base import exceptions, libutils, resourceobserver, taskhandle +from rope.base import ( + exceptions, + libutils, + resourceobserver, + taskhandle, +) from rope.base.project import Project from rope.base.resources import Resource from rope.contrib.autoimport.defs import ( diff --git a/rope/contrib/codeassist.py b/rope/contrib/codeassist.py index 334c78c4a..1c28e1883 100644 --- a/rope/contrib/codeassist.py +++ b/rope/contrib/codeassist.py @@ -4,15 +4,17 @@ import rope.base.codeanalyze import rope.base.evaluate -from rope.base import builtins -from rope.base import exceptions -from rope.base import libutils -from rope.base import pynames -from rope.base import pynamesdef -from rope.base import pyobjects -from rope.base import pyobjectsdef -from rope.base import pyscopes -from rope.base import worder +from rope.base import ( + builtins, + exceptions, + libutils, + pynames, + pynamesdef, + pyobjects, + pyobjectsdef, + pyscopes, + worder, +) from rope.contrib import fixsyntax from rope.refactor import functionutils diff --git a/rope/contrib/findit.py b/rope/contrib/findit.py index 027248eb0..5952c1ac8 100644 --- a/rope/contrib/findit.py +++ b/rope/contrib/findit.py @@ -1,7 +1,7 @@ import rope.base.codeanalyze import rope.base.evaluate import rope.base.pyobjects -from rope.base import taskhandle, exceptions, worder +from rope.base import exceptions, taskhandle, worder from rope.contrib import fixsyntax from rope.refactor import occurrences diff --git a/rope/contrib/fixsyntax.py b/rope/contrib/fixsyntax.py index b1e96935e..28c91bb4f 100644 --- a/rope/contrib/fixsyntax.py +++ b/rope/contrib/fixsyntax.py @@ -1,9 +1,11 @@ import rope.base.codeanalyze import rope.base.evaluate -from rope.base import exceptions -from rope.base import libutils -from rope.base import utils -from rope.base import worder +from rope.base import ( + exceptions, + libutils, + utils, + worder, +) from rope.base.codeanalyze import ArrayLinesAdapter, LogicalLineFinder diff --git a/rope/contrib/generate.py b/rope/contrib/generate.py index 0d6b91e35..c2c028c72 100644 --- a/rope/contrib/generate.py +++ b/rope/contrib/generate.py @@ -1,6 +1,13 @@ import rope.base.evaluate -from rope.base import libutils -from rope.base import change, pyobjects, exceptions, pynames, worder, codeanalyze +from rope.base import ( + change, + codeanalyze, + exceptions, + libutils, + pynames, + pyobjects, + worder, +) from rope.refactor import sourceutils, importutils, functionutils, suites diff --git a/rope/refactor/change_signature.py b/rope/refactor/change_signature.py index 15c360cdc..42d6082f1 100644 --- a/rope/refactor/change_signature.py +++ b/rope/refactor/change_signature.py @@ -1,12 +1,14 @@ import copy import rope.base.exceptions -from rope.base import codeanalyze -from rope.base import evaluate -from rope.base import pyobjects -from rope.base import taskhandle -from rope.base import utils -from rope.base import worder +from rope.base import ( + codeanalyze, + evaluate, + pyobjects, + taskhandle, + utils, + worder, +) from rope.base.change import ChangeContents, ChangeSet from rope.refactor import occurrences, functionutils diff --git a/rope/refactor/encapsulate_field.py b/rope/refactor/encapsulate_field.py index 1d454d6e2..ba18b2b54 100644 --- a/rope/refactor/encapsulate_field.py +++ b/rope/refactor/encapsulate_field.py @@ -1,10 +1,12 @@ -from rope.base import evaluate -from rope.base import exceptions -from rope.base import libutils -from rope.base import pynames -from rope.base import taskhandle -from rope.base import utils -from rope.base import worder +from rope.base import ( + evaluate, + exceptions, + libutils, + pynames, + taskhandle, + utils, + worder, +) from rope.base.change import ChangeSet, ChangeContents from rope.refactor import sourceutils, occurrences diff --git a/rope/refactor/inline.py b/rope/refactor/inline.py index f7fbe3bfe..001a33a28 100644 --- a/rope/refactor/inline.py +++ b/rope/refactor/inline.py @@ -22,15 +22,14 @@ import rope.base.exceptions import rope.refactor.functionutils from rope.base import ( - ast, + codeanalyze, + evaluate, + libutils, pynames, pyobjects, - codeanalyze, taskhandle, - evaluate, - worder, utils, - libutils, + worder, ) from rope.base.change import ChangeSet, ChangeContents from rope.refactor import ( diff --git a/rope/refactor/introduce_factory.py b/rope/refactor/introduce_factory.py index a36935c9e..a528b97d0 100644 --- a/rope/refactor/introduce_factory.py +++ b/rope/refactor/introduce_factory.py @@ -1,7 +1,6 @@ import rope.base.exceptions import rope.base.pyobjects -from rope.base import libutils -from rope.base import taskhandle, evaluate +from rope.base import evaluate, libutils, taskhandle from rope.base.change import ChangeSet, ChangeContents from rope.refactor import rename, occurrences, sourceutils, importutils diff --git a/rope/refactor/introduce_parameter.py b/rope/refactor/introduce_parameter.py index 5f1446c40..df7310969 100644 --- a/rope/refactor/introduce_parameter.py +++ b/rope/refactor/introduce_parameter.py @@ -1,5 +1,10 @@ import rope.base.change -from rope.base import exceptions, evaluate, worder, codeanalyze +from rope.base import ( + codeanalyze, + exceptions, + evaluate, + worder, +) from rope.refactor import functionutils, sourceutils, occurrences diff --git a/rope/refactor/localtofield.py b/rope/refactor/localtofield.py index ea2c125b9..56a383b8d 100644 --- a/rope/refactor/localtofield.py +++ b/rope/refactor/localtofield.py @@ -1,4 +1,9 @@ -from rope.base import pynames, evaluate, exceptions, worder +from rope.base import ( + evaluate, + exceptions, + pynames, + worder, +) from rope.refactor.rename import Rename diff --git a/rope/refactor/method_object.py b/rope/refactor/method_object.py index e0406b6ee..cada6fcc8 100644 --- a/rope/refactor/method_object.py +++ b/rope/refactor/method_object.py @@ -1,7 +1,13 @@ import warnings -from rope.base import libutils -from rope.base import pyobjects, exceptions, change, evaluate, codeanalyze +from rope.base import ( + change, + codeanalyze, + evaluate, + exceptions, + libutils, + pyobjects, +) from rope.refactor import sourceutils, occurrences, rename diff --git a/rope/refactor/move.py b/rope/refactor/move.py index c4ccd8970..7feacb1c8 100644 --- a/rope/refactor/move.py +++ b/rope/refactor/move.py @@ -5,14 +5,14 @@ """ from rope.base import ( - pyobjects, codeanalyze, + evaluate, exceptions, + libutils, pynames, + pyobjects, taskhandle, - evaluate, worder, - libutils, ) from rope.base.change import ChangeSet, ChangeContents, MoveResource from rope.refactor import importutils, rename, occurrences, sourceutils, functionutils diff --git a/rope/refactor/multiproject.py b/rope/refactor/multiproject.py index a13625dfa..f829de31d 100644 --- a/rope/refactor/multiproject.py +++ b/rope/refactor/multiproject.py @@ -5,7 +5,7 @@ """ -from rope.base import resources, libutils +from rope.base import libutils, resources class MultiProjectRefactoring: diff --git a/rope/refactor/wildcards.py b/rope/refactor/wildcards.py index 5d7260dfc..4a57a8aba 100644 --- a/rope/refactor/wildcards.py +++ b/rope/refactor/wildcards.py @@ -1,4 +1,5 @@ -from rope.base import ast, evaluate, builtins, pyobjects +import ast +from rope.base import evaluate, builtins, pyobjects from rope.refactor import patchedast, occurrences diff --git a/ropetest/contrib/autoimport/conftest.py b/ropetest/contrib/autoimport/conftest.py index b0aaa6d0d..51ce09fab 100644 --- a/ropetest/contrib/autoimport/conftest.py +++ b/ropetest/contrib/autoimport/conftest.py @@ -1,7 +1,6 @@ import pathlib import pytest - from ropetest import testutils diff --git a/ropetest/contrib/codeassisttest.py b/ropetest/contrib/codeassisttest.py index f1eaf3e7b..24503d09a 100644 --- a/ropetest/contrib/codeassisttest.py +++ b/ropetest/contrib/codeassisttest.py @@ -1341,7 +1341,7 @@ def _underlined_func(): def tearDown(self): testutils.remove_project(self.project) - super(self.__class__, self).tearDown() + super().tearDown() def _assist(self, code, resource=None, **kwds): return code_assist(self.project, code, len(code), resource, **kwds) diff --git a/ropetest/projecttest.py b/ropetest/projecttest.py index 1a66bfd3d..ff71f0171 100644 --- a/ropetest/projecttest.py +++ b/ropetest/projecttest.py @@ -1,8 +1,7 @@ import os.path import shutil from textwrap import dedent - -import pytest +import unittest from rope.base.exceptions import RopeError, ResourceNotFoundError from rope.base.fscommands import FileSystemCommands @@ -12,9 +11,6 @@ from ropetest import testutils -import unittest - - class ProjectTest(unittest.TestCase): def setUp(self): unittest.TestCase.setUp(self) @@ -1011,7 +1007,7 @@ def test_none_project_rope_folder(self): def test_getting_project_rope_folder(self): self.project = testutils.sample_project(ropefolder=".ropeproject") self.assertTrue(self.project.ropefolder.exists()) - self.assertTrue(".ropeproject", self.project.ropefolder.path) + self.assertEqual(".ropeproject", self.project.ropefolder.path) def test_setting_ignored_resources(self): self.project = testutils.sample_project(ignored_resources=["myfile.txt"]) @@ -1063,7 +1059,7 @@ def test_normal_fscommands(self): self.project = testutils.sample_project(fscommands=fscommands) myfile = self.project.get_file("myfile.txt") myfile.create() - self.assertTrue("create_file ", fscommands.log) + self.assertEqual("create_file ", fscommands.log) def test_fscommands_and_ignored_resources(self): fscommands = _MockFSCommands() @@ -1079,7 +1075,7 @@ def test_deprecated_fscommands(self): self.project = testutils.sample_project(fscommands=fscommands) myfile = self.project.get_file("myfile.txt") myfile.create() - self.assertTrue("create_file ", fscommands.log) + self.assertEqual("create_file ", fscommands.log) def test_ignored_resources_and_prefixes(self): self.project = testutils.sample_project(ignored_resources=[".hg"]) diff --git a/ropetest/pycoretest.py b/ropetest/pycoretest.py index 4ae90c369..7a0a7833b 100644 --- a/ropetest/pycoretest.py +++ b/ropetest/pycoretest.py @@ -776,7 +776,7 @@ def test_pyobject_equality_should_compare_types(self): class PyCoreInProjectsTest(unittest.TestCase): def setUp(self): - super(self.__class__, self).setUp() + super().setUp() self.project = testutils.sample_project() self.pycore = self.project.pycore samplemod = testutils.create_module(self.project, "samplemod") @@ -799,7 +799,7 @@ def _underlined_func(): def tearDown(self): testutils.remove_project(self.project) - super(self.__class__, self).tearDown() + super().tearDown() def test_simple_import(self): code = "import samplemod\n" diff --git a/ropetest/refactor/patchedasttest.py b/ropetest/refactor/patchedasttest.py index d24f2c5aa..6eee8921b 100644 --- a/ropetest/refactor/patchedasttest.py +++ b/ropetest/refactor/patchedasttest.py @@ -1,8 +1,9 @@ +import ast import unittest import sys from textwrap import dedent -from rope.base import ast +from rope.base.ast import call_for_nodes from rope.refactor import patchedast from ropetest import testutils @@ -12,12 +13,6 @@ class PatchedASTTest(unittest.TestCase): - def setUp(self): - super().setUp() - - def tearDown(self): - super().tearDown() - def assert_single_case_match_block(self, checker, match_type): checker.check_children("Match", [ "match", @@ -1651,7 +1646,7 @@ def __call__(self, node): return self.result is not None search = Search() - ast.call_for_nodes(self.ast, search, recursive=True) + call_for_nodes(self.ast, search, recursive=True) return search.result def check_children(self, text, children): diff --git a/ropetest/refactor/suitestest.py b/ropetest/refactor/suitestest.py index 5c5fa1fbd..f61dc12e3 100644 --- a/ropetest/refactor/suitestest.py +++ b/ropetest/refactor/suitestest.py @@ -2,18 +2,12 @@ import unittest -from rope.base import ast +from rope.base import astwrapper from rope.refactor import suites from ropetest import testutils class SuiteTest(unittest.TestCase): - def setUp(self): - super().setUp() - - def tearDown(self): - super().tearDown() - def test_trivial_case(self): root = source_suite_tree("") self.assertEqual(1, root.get_start()) @@ -218,4 +212,4 @@ def test_match_case(self): def source_suite_tree(source): - return suites.ast_suite_tree(ast.parse(source)) + return suites.ast_suite_tree(astwrapper.parse(source))