From aa2f173a7f6d436098f716586a84f4ffa97c8914 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sat, 17 Dec 2022 08:37:01 -0600 Subject: [PATCH 01/99] Suppress mypy complaints. Change a few annotations --- rope/base/fscommands.py | 8 ++++---- rope/base/oi/doa.py | 4 ++-- rope/base/oi/runmod.py | 4 ++-- rope/base/oi/soa.py | 10 ++++++++-- rope/base/oi/type_hinting/evaluate.py | 1 + .../oi/type_hinting/providers/numpydocstrings.py | 6 +++--- rope/base/oi/type_hinting/utils.py | 8 +++++--- rope/base/prefs.py | 1 + rope/base/project.py | 4 ++-- rope/base/pycore.py | 14 ++++++++------ rope/contrib/autoimport/sqlite.py | 2 +- rope/refactor/extract.py | 3 ++- rope/refactor/importutils/importinfo.py | 3 ++- 13 files changed, 41 insertions(+), 27 deletions(-) diff --git a/rope/base/fscommands.py b/rope/base/fscommands.py index 1357beaf7..034cf2e32 100644 --- a/rope/base/fscommands.py +++ b/rope/base/fscommands.py @@ -65,7 +65,7 @@ def read(self, path): class SubversionCommands: def __init__(self, *args): self.normal_actions = FileSystemCommands() - import pysvn + import pysvn # type:ignore self.client = pysvn.Client() @@ -115,9 +115,9 @@ def __init__(self, root): self.repo = self.hg.hg.repository(self.ui, root) def _import_mercurial(self): - import mercurial.commands - import mercurial.hg - import mercurial.ui + import mercurial.commands # type:ignore + import mercurial.hg # type:ignore + import mercurial.ui # type:ignore return mercurial diff --git a/rope/base/oi/doa.py b/rope/base/oi/doa.py index 9ad4e2d17..acc1abf8b 100644 --- a/rope/base/oi/doa.py +++ b/rope/base/oi/doa.py @@ -3,9 +3,9 @@ import hmac try: - import cPickle as pickle + import cPickle as pickle # type:ignore except ImportError: - import pickle + import pickle # type:ignore import marshal import os import socket diff --git a/rope/base/oi/runmod.py b/rope/base/oi/runmod.py index 0cdb3c6b8..65dba8b83 100644 --- a/rope/base/oi/runmod.py +++ b/rope/base/oi/runmod.py @@ -4,9 +4,9 @@ def __rope_start_everything(): import socket try: - import cPickle as pickle + import cPickle as pickle # type:ignore except ImportError: - import pickle + import pickle # type:ignore import marshal import inspect import types diff --git a/rope/base/oi/soa.py b/rope/base/oi/soa.py index ba28449ea..548870536 100644 --- a/rope/base/oi/soa.py +++ b/rope/base/oi/soa.py @@ -1,10 +1,11 @@ +from typing import Callable import rope.base.ast import rope.base.oi.soi import rope.base.pynames from rope.base import pyobjects, evaluate, nameanalyze, arguments -def analyze_module(pycore, pymodule, should_analyze, search_subscopes, followed_calls): +def analyze_module(pycore, pymodule, should_analyze, search_subscopes, followed_calls: bool): """Analyze `pymodule` for static object inference Analyzes scopes for collecting object information. The analysis @@ -14,7 +15,12 @@ def analyze_module(pycore, pymodule, should_analyze, search_subscopes, followed_ _analyze_node(pycore, pymodule, should_analyze, search_subscopes, followed_calls) -def _analyze_node(pycore, pydefined, should_analyze, search_subscopes, followed_calls): +def _analyze_node(pycore, + pydefined, + should_analyze: Callable, + search_subscopes: Callable, + followed_calls: bool, +) -> None: if search_subscopes(pydefined): for scope in pydefined.get_scope().get_scopes(): _analyze_node( diff --git a/rope/base/oi/type_hinting/evaluate.py b/rope/base/oi/type_hinting/evaluate.py index 6e4a06bc3..76549298f 100644 --- a/rope/base/oi/type_hinting/evaluate.py +++ b/rope/base/oi/type_hinting/evaluate.py @@ -1,3 +1,4 @@ +# type: ignore # Based on super lightweight Simple Top-Down Parser from http://effbot.org/zone/simple-top-down-parsing.htm # and https://bitbucket.org/emacsway/sqlbuilder/src/default/sqlbuilder/smartsql/contrib/evaluate.py import re diff --git a/rope/base/oi/type_hinting/providers/numpydocstrings.py b/rope/base/oi/type_hinting/providers/numpydocstrings.py index 5305a0d11..d5cee7733 100644 --- a/rope/base/oi/type_hinting/providers/numpydocstrings.py +++ b/rope/base/oi/type_hinting/providers/numpydocstrings.py @@ -5,10 +5,10 @@ """ import re from rope.base.ast import literal_eval -from rope.base.oi.type_hinting.providers import docstrings +from rope.base.oi.type_hinting.providers import docstrings # type:ignore try: - from numpydoc.docscrape import NumpyDocString + from numpydoc.docscrape import NumpyDocString # type:ignore except ImportError: NumpyDocString = None @@ -39,4 +39,4 @@ def __call__(self, docstring, param_name): if not NumpyDocString: - NumPyDocstringParamParser = _DummyParamParser + NumPyDocstringParamParser = _DummyParamParser # type:ignore diff --git a/rope/base/oi/type_hinting/utils.py b/rope/base/oi/type_hinting/utils.py index 37a2568b6..c9390c013 100644 --- a/rope/base/oi/type_hinting/utils.py +++ b/rope/base/oi/type_hinting/utils.py @@ -1,5 +1,5 @@ import logging -from typing import Union, Optional +from typing import Optional, Tuple import rope.base.utils as base_utils from rope.base import evaluate @@ -73,8 +73,10 @@ def get_mro(pyclass): return class_list -def resolve_type(type_name, pyobject): - # type: (str, Union[PyDefinedObject, PyObject]) -> Optional[PyDefinedObject, PyObject] +def resolve_type( + type_name: str, + pyobject: PyDefinedObject, +) -> Optional[Tuple[PyDefinedObject, PyObject]]: """ Find proper type object from its name. """ diff --git a/rope/base/prefs.py b/rope/base/prefs.py index a7d47b844..062199f39 100644 --- a/rope/base/prefs.py +++ b/rope/base/prefs.py @@ -1,3 +1,4 @@ +# type: ignore """Rope preferences.""" from dataclasses import asdict, dataclass from textwrap import dedent diff --git a/rope/base/project.py b/rope/base/project.py index 5fc74ef3d..1b1905f41 100644 --- a/rope/base/project.py +++ b/rope/base/project.py @@ -16,9 +16,9 @@ import rope.base.resourceobserver as resourceobserver try: - import cPickle as pickle + import cPickle as pickle # type:ignore except ImportError: - import pickle + import pickle # type:ignore class _Project: diff --git a/rope/base/pycore.py b/rope/base/pycore.py index abab0120e..74f7d8948 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -1,5 +1,6 @@ import bisect import difflib +from typing import Callable import warnings import rope.base.libutils @@ -186,17 +187,18 @@ def run_module(self, resource, args=None, stdin=None, stdout=None): def analyze_module( self, resource, - should_analyze=lambda py: True, - search_subscopes=lambda py: True, + should_analyze: Callable=lambda py: True, + search_subscopes: Callable=lambda py: True, followed_calls=None, ): """Analyze `resource` module for static object inference This function forces rope to analyze this module to collect - information about function calls. `should_analyze` is a - function that is called with a `PyDefinedObject` argument. If - it returns `True` the element is analyzed. If it is `None` or - returns `False` the element is not analyzed. + information about function calls. + + `should_analyze` is a function that is called with a `PyDefinedObject` + argument. If it returns `True` the element is analyzed. If it is `None` + or returns `False` the element is not analyzed. `search_subscopes` is like `should_analyze`; The difference is that if it returns `False` the sub-scopes are all ignored. diff --git a/rope/contrib/autoimport/sqlite.py b/rope/contrib/autoimport/sqlite.py index 381aa99e0..9ec005d56 100644 --- a/rope/contrib/autoimport/sqlite.py +++ b/rope/contrib/autoimport/sqlite.py @@ -438,7 +438,7 @@ def filter_folders(folder: Path) -> bool: folders = self.project.get_python_path_folders() folder_paths = map(lambda folder: Path(folder.real_path), folders) - folder_paths = filter(filter_folders, folder_paths) + folder_paths = filter(filter_folders, folder_paths) # type:ignore return list(OrderedDict.fromkeys(folder_paths)) def _get_available_packages(self) -> List[Package]: diff --git a/rope/refactor/extract.py b/rope/refactor/extract.py index 3221b1a16..499615133 100644 --- a/rope/refactor/extract.py +++ b/rope/refactor/extract.py @@ -1,6 +1,7 @@ import re from contextlib import contextmanager from itertools import chain +from typing import Dict from rope.base import ast, codeanalyze from rope.base.change import ChangeSet, ChangeContents @@ -35,7 +36,7 @@ # classes. class _ExtractRefactoring: - kind_prefixes = {} + kind_prefixes: Dict[str, str] = {} def __init__(self, project, resource, start_offset, end_offset, variable=False): self.project = project diff --git a/rope/refactor/importutils/importinfo.py b/rope/refactor/importutils/importinfo.py index 12fb6eca9..f8e2932de 100644 --- a/rope/refactor/importutils/importinfo.py +++ b/rope/refactor/importutils/importinfo.py @@ -1,3 +1,4 @@ +from typing import List class ImportStatement: """Represent an import in a module @@ -188,7 +189,7 @@ def is_star_import(self): class EmptyImport(ImportInfo): - names_and_aliases = [] + names_and_aliases: List = [] def is_empty(self): return True From d18aeb642b6397e22471b97ceae71c5e89cf2000 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sat, 17 Dec 2022 08:58:22 -0600 Subject: [PATCH 02/99] Blacken three files --- rope/base/oi/soa.py | 7 +++++-- rope/base/pycore.py | 6 +++--- rope/refactor/importutils/importinfo.py | 2 ++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/rope/base/oi/soa.py b/rope/base/oi/soa.py index 548870536..e797a2c93 100644 --- a/rope/base/oi/soa.py +++ b/rope/base/oi/soa.py @@ -5,7 +5,9 @@ from rope.base import pyobjects, evaluate, nameanalyze, arguments -def analyze_module(pycore, pymodule, should_analyze, search_subscopes, followed_calls: bool): +def analyze_module( + pycore, pymodule, should_analyze, search_subscopes, followed_calls: bool +): """Analyze `pymodule` for static object inference Analyzes scopes for collecting object information. The analysis @@ -15,7 +17,8 @@ def analyze_module(pycore, pymodule, should_analyze, search_subscopes, followed_ _analyze_node(pycore, pymodule, should_analyze, search_subscopes, followed_calls) -def _analyze_node(pycore, +def _analyze_node( + pycore, pydefined, should_analyze: Callable, search_subscopes: Callable, diff --git a/rope/base/pycore.py b/rope/base/pycore.py index 74f7d8948..e9f291dc9 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -187,15 +187,15 @@ def run_module(self, resource, args=None, stdin=None, stdout=None): def analyze_module( self, resource, - should_analyze: Callable=lambda py: True, - search_subscopes: Callable=lambda py: True, + should_analyze: Callable = lambda py: True, + search_subscopes: Callable = lambda py: True, followed_calls=None, ): """Analyze `resource` module for static object inference This function forces rope to analyze this module to collect information about function calls. - + `should_analyze` is a function that is called with a `PyDefinedObject` argument. If it returns `True` the element is analyzed. If it is `None` or returns `False` the element is not analyzed. diff --git a/rope/refactor/importutils/importinfo.py b/rope/refactor/importutils/importinfo.py index f8e2932de..3804592ae 100644 --- a/rope/refactor/importutils/importinfo.py +++ b/rope/refactor/importutils/importinfo.py @@ -1,4 +1,6 @@ from typing import List + + class ImportStatement: """Represent an import in a module From 6845ac49f521fc27a70bf4c51013f2ff8833d6f7 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 1 Jan 2023 10:11:02 -0600 Subject: [PATCH 03/99] Define Tuple --- rope/base/oi/type_hinting/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rope/base/oi/type_hinting/utils.py b/rope/base/oi/type_hinting/utils.py index 5afdf5f02..c9390c013 100644 --- a/rope/base/oi/type_hinting/utils.py +++ b/rope/base/oi/type_hinting/utils.py @@ -1,5 +1,5 @@ import logging -from typing import Optional, Union +from typing import Optional, Tuple import rope.base.utils as base_utils from rope.base import evaluate From 82d4a175dc9df3ee5b82322328ff7ab6c0a88972 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Mon, 2 Jan 2023 13:13:38 -0600 Subject: [PATCH 04/99] Add annotations --- rope/base/evaluate.py | 8 ++++++-- rope/base/oi/type_hinting/evaluate.py | 1 + rope/base/oi/type_hinting/utils.py | 5 ++--- rope/base/prefs.py | 1 + rope/refactor/importutils/module_imports.py | 14 +++++++++----- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/rope/base/evaluate.py b/rope/base/evaluate.py index d9bef3cdb..aa07cfa9f 100644 --- a/rope/base/evaluate.py +++ b/rope/base/evaluate.py @@ -1,5 +1,6 @@ +from __future__ import annotations from operator import itemgetter -from typing import Optional, Tuple +from typing import Optional, Tuple, TYPE_CHECKING import rope.base.builtins import rope.base.pynames @@ -14,6 +15,9 @@ worder, ) +if TYPE_CHECKING: + from rope.base.pyscopes import Scope + BadIdentifierError = exceptions.BadIdentifierError @@ -158,7 +162,7 @@ def _find_module(self, module_name): class StatementEvaluator(ast.RopeNodeVisitor): - def __init__(self, scope): + def __init__(self, scope: Scope): self.scope = scope self.result = None self.old_result = None diff --git a/rope/base/oi/type_hinting/evaluate.py b/rope/base/oi/type_hinting/evaluate.py index 610c67978..ff8af387d 100644 --- a/rope/base/oi/type_hinting/evaluate.py +++ b/rope/base/oi/type_hinting/evaluate.py @@ -1,3 +1,4 @@ +# type:ignore # Based on super lightweight Simple Top-Down Parser from http://effbot.org/zone/simple-top-down-parsing.htm # and https://bitbucket.org/emacsway/sqlbuilder/src/default/sqlbuilder/smartsql/contrib/evaluate.py import re diff --git a/rope/base/oi/type_hinting/utils.py b/rope/base/oi/type_hinting/utils.py index a2f90bf8b..a8c381fc5 100644 --- a/rope/base/oi/type_hinting/utils.py +++ b/rope/base/oi/type_hinting/utils.py @@ -1,5 +1,5 @@ import logging -from typing import Optional, Union +from typing import Optional, Tuple import rope.base.utils as base_utils from rope.base import evaluate @@ -73,8 +73,7 @@ def get_mro(pyclass): return class_list -def resolve_type(type_name, pyobject): - # type: (str, Union[PyDefinedObject, PyObject]) -> Optional[PyDefinedObject, PyObject] +def resolve_type(type_name: str, pyobject: PyObject) -> Optional[Tuple[PyDefinedObject, PyObject]]: """ Find proper type object from its name. """ diff --git a/rope/base/prefs.py b/rope/base/prefs.py index 95fc31877..c5eac7478 100644 --- a/rope/base/prefs.py +++ b/rope/base/prefs.py @@ -1,3 +1,4 @@ +# type: ignore """Rope preferences.""" from dataclasses import asdict, dataclass from textwrap import dedent diff --git a/rope/refactor/importutils/module_imports.py b/rope/refactor/importutils/module_imports.py index d8e99df5d..1f60ef9c3 100644 --- a/rope/refactor/importutils/module_imports.py +++ b/rope/refactor/importutils/module_imports.py @@ -1,11 +1,15 @@ -from typing import List, Union +from __future__ import annotations +from typing import Callable, List, Union, TYPE_CHECKING from rope.base import ast, exceptions, pynames, pynamesdef, utils from rope.refactor.importutils import actions, importinfo +if TYPE_CHECKING: + from rope.base.pyobjects import PyModule, PyObject + class ModuleImports: - def __init__(self, project, pymodule, import_filter=None): + def __init__(self, project: PyObject, pymodule: PyModule, import_filter: Callable=None): self.project = project self.pymodule = pymodule self.separating_lines = 0 @@ -392,7 +396,7 @@ def _count_blank_lines(get_line, start, end, step=1): class _OneTimeSelector: - def __init__(self, names): + def __init__(self, names: List[str]): self.names = names self.selected_names = set() @@ -416,7 +420,7 @@ def _can_name_be_added(self, imported_primary): class _UnboundNameFinder(ast.RopeNodeVisitor): - def __init__(self, pyobject): + def __init__(self, pyobject: PyObject): self.pyobject = pyobject def _visit_child_scope(self, node): @@ -466,7 +470,7 @@ def add_unbound(self, name): class _GlobalUnboundNameFinder(_UnboundNameFinder): - def __init__(self, pymodule, wanted_pyobject): + def __init__(self, pymodule: PyModule, wanted_pyobject: PyObject): super().__init__(pymodule) self.unbound = set() self.names = set() From 001d5fd6a8d48cd26cb9c60477e446292a7c00e8 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Mon, 2 Jan 2023 13:37:15 -0600 Subject: [PATCH 05/99] More annotations --- rope/base/nameanalyze.py | 3 ++- rope/base/pyobjectsdef.py | 6 +++--- rope/contrib/finderrors.py | 5 +++-- rope/refactor/extract.py | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/rope/base/nameanalyze.py b/rope/base/nameanalyze.py index fd7f1d2ea..5591ff2bd 100644 --- a/rope/base/nameanalyze.py +++ b/rope/base/nameanalyze.py @@ -1,3 +1,4 @@ +from typing import List from rope.base import ast @@ -19,7 +20,7 @@ def get_name_levels(node): class _NodeNameCollector(ast.RopeNodeVisitor): - def __init__(self, levels=None): + def __init__(self, levels: List[int]=None): self.names = [] self.levels = levels self.index = 0 diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 079b4c8cd..2bb374233 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -292,7 +292,7 @@ def get_name(self): class _AnnAssignVisitor(ast.RopeNodeVisitor): - def __init__(self, scope_visitor): + def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None self.type_hint = None @@ -334,7 +334,7 @@ def _Slice(self, node): class _ExpressionVisitor(ast.RopeNodeVisitor): - def __init__(self, scope_visitor): + def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor def _assigned(self, name, assignment=None): @@ -361,7 +361,7 @@ def _NamedExpr(self, node): class _AssignVisitor(ast.RopeNodeVisitor): - def __init__(self, scope_visitor): + def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None diff --git a/rope/contrib/finderrors.py b/rope/contrib/finderrors.py index 335e6d84a..bc881f948 100644 --- a/rope/contrib/finderrors.py +++ b/rope/contrib/finderrors.py @@ -24,6 +24,7 @@ """ from rope.base import ast, evaluate, pyobjects +from rope.base.pyobjects import PyModule, PyScope def find_errors(project, resource): @@ -38,9 +39,9 @@ def find_errors(project, resource): class _BadAccessFinder(ast.RopeNodeVisitor): - def __init__(self, pymodule): + def __init__(self, pymodule: PyModule): self.pymodule = pymodule - self.scope = pymodule.get_scope() + self.scope: PyScope = pymodule.get_scope() self.errors = [] def _Name(self, node): diff --git a/rope/refactor/extract.py b/rope/refactor/extract.py index 5e4d4fddf..af6a0bb3e 100644 --- a/rope/refactor/extract.py +++ b/rope/refactor/extract.py @@ -516,7 +516,7 @@ def _is_on_a_word(self, info, offset): class _ExtractMethodParts(ast.RopeNodeVisitor): def __init__(self, info): - self.info = info + self.info: str = info self.info_collector = self._create_info_collector() self.info.kind = self._get_kind_by_scope() self._check_constraints() @@ -778,7 +778,7 @@ def get_checks(self): class _FunctionInformationCollector(ast.RopeNodeVisitor): - def __init__(self, start, end, is_global): + def __init__(self, start: int, end: int, is_global: bool): self.start = start self.end = end self.is_global = is_global From a4a5f51f2df4b7b98061a2c3647927690083317f Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Mon, 2 Jan 2023 13:50:51 -0600 Subject: [PATCH 06/99] Still more annotations --- rope/base/nameanalyze.py | 4 ++-- .../oi/type_hinting/providers/numpydocstrings.py | 1 + rope/base/oi/type_hinting/utils.py | 4 +++- rope/contrib/finderrors.py | 8 +++++--- rope/refactor/extract.py | 3 ++- rope/refactor/importutils/importinfo.py | 5 ++++- rope/refactor/importutils/module_imports.py | 12 +++++++----- 7 files changed, 24 insertions(+), 13 deletions(-) diff --git a/rope/base/nameanalyze.py b/rope/base/nameanalyze.py index 5591ff2bd..e98a4ac7b 100644 --- a/rope/base/nameanalyze.py +++ b/rope/base/nameanalyze.py @@ -20,8 +20,8 @@ def get_name_levels(node): class _NodeNameCollector(ast.RopeNodeVisitor): - def __init__(self, levels: List[int]=None): - self.names = [] + def __init__(self, levels: List[int] = None): + self.names: List[str] = [] self.levels = levels self.index = 0 diff --git a/rope/base/oi/type_hinting/providers/numpydocstrings.py b/rope/base/oi/type_hinting/providers/numpydocstrings.py index 14c6cc442..0b4524400 100644 --- a/rope/base/oi/type_hinting/providers/numpydocstrings.py +++ b/rope/base/oi/type_hinting/providers/numpydocstrings.py @@ -1,3 +1,4 @@ +# type: ignore """ Some code extracted (or based on code) from: https://github.com/davidhalter/jedi/blob/b489019f5bd5750051122b94cc767df47751ecb7/jedi/evaluate/docstrings.py diff --git a/rope/base/oi/type_hinting/utils.py b/rope/base/oi/type_hinting/utils.py index a8c381fc5..caffd61ed 100644 --- a/rope/base/oi/type_hinting/utils.py +++ b/rope/base/oi/type_hinting/utils.py @@ -73,7 +73,9 @@ def get_mro(pyclass): return class_list -def resolve_type(type_name: str, pyobject: PyObject) -> Optional[Tuple[PyDefinedObject, PyObject]]: +def resolve_type( + type_name: str, pyobject: PyObject +) -> Optional[Tuple[PyDefinedObject, PyObject]]: """ Find proper type object from its name. """ diff --git a/rope/contrib/finderrors.py b/rope/contrib/finderrors.py index bc881f948..4022b2d6c 100644 --- a/rope/contrib/finderrors.py +++ b/rope/contrib/finderrors.py @@ -23,8 +23,10 @@ * ... ;-) """ +from typing import List from rope.base import ast, evaluate, pyobjects -from rope.base.pyobjects import PyModule, PyScope +from rope.base.pyobjects import PyModule +from rope.base.pyscopes import Scope def find_errors(project, resource): @@ -41,8 +43,8 @@ def find_errors(project, resource): class _BadAccessFinder(ast.RopeNodeVisitor): def __init__(self, pymodule: PyModule): self.pymodule = pymodule - self.scope: PyScope = pymodule.get_scope() - self.errors = [] + self.scope: Scope = pymodule.get_scope() + self.errors: List[Error] = [] def _Name(self, node): if isinstance(node.ctx, (ast.Store, ast.Param)): diff --git a/rope/refactor/extract.py b/rope/refactor/extract.py index af6a0bb3e..f6e0953ac 100644 --- a/rope/refactor/extract.py +++ b/rope/refactor/extract.py @@ -1,4 +1,5 @@ import re +from typing import Dict from contextlib import contextmanager from itertools import chain @@ -35,7 +36,7 @@ # classes. class _ExtractRefactoring: - kind_prefixes = {} + kind_prefixes: Dict[str, str] = {} def __init__(self, project, resource, start_offset, end_offset, variable=False): self.project = project diff --git a/rope/refactor/importutils/importinfo.py b/rope/refactor/importutils/importinfo.py index 12fb6eca9..18b6646b2 100644 --- a/rope/refactor/importutils/importinfo.py +++ b/rope/refactor/importutils/importinfo.py @@ -1,3 +1,6 @@ +from typing import List + + class ImportStatement: """Represent an import in a module @@ -188,7 +191,7 @@ def is_star_import(self): class EmptyImport(ImportInfo): - names_and_aliases = [] + names_and_aliases: List[str] = [] def is_empty(self): return True diff --git a/rope/refactor/importutils/module_imports.py b/rope/refactor/importutils/module_imports.py index 1f60ef9c3..508934a89 100644 --- a/rope/refactor/importutils/module_imports.py +++ b/rope/refactor/importutils/module_imports.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import Callable, List, Union, TYPE_CHECKING +from typing import Callable, List, Set, Union, TYPE_CHECKING from rope.base import ast, exceptions, pynames, pynamesdef, utils from rope.refactor.importutils import actions, importinfo @@ -9,7 +9,9 @@ class ModuleImports: - def __init__(self, project: PyObject, pymodule: PyModule, import_filter: Callable=None): + def __init__( + self, project: PyObject, pymodule: PyModule, import_filter: Callable = None + ): self.project = project self.pymodule = pymodule self.separating_lines = 0 @@ -398,7 +400,7 @@ def _count_blank_lines(get_line, start, end, step=1): class _OneTimeSelector: def __init__(self, names: List[str]): self.names = names - self.selected_names = set() + self.selected_names: Set = set() def __call__(self, imported_primary): if self._can_name_be_added(imported_primary): @@ -472,8 +474,8 @@ def add_unbound(self, name): class _GlobalUnboundNameFinder(_UnboundNameFinder): def __init__(self, pymodule: PyModule, wanted_pyobject: PyObject): super().__init__(pymodule) - self.unbound = set() - self.names = set() + self.unbound: Set = set() + self.names: Set = set() for name, pyname in pymodule._get_structural_attributes().items(): if not isinstance(pyname, (pynames.ImportedName, pynames.ImportedModule)): self.names.add(name) From e121c8f980e879196f6543e4617af56dbc248e15 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Tue, 3 Jan 2023 10:04:32 -0600 Subject: [PATCH 07/99] Alphabetize imports, removing duplicates --- rope/base/oi/runmod.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rope/base/oi/runmod.py b/rope/base/oi/runmod.py index ad1345fb7..6db81f655 100644 --- a/rope/base/oi/runmod.py +++ b/rope/base/oi/runmod.py @@ -7,10 +7,6 @@ def __rope_start_everything(): import cPickle as pickle # type:ignore except ImportError: import pickle # type:ignore - import marshal - import inspect - import types - import threading import base64 import hashlib import hmac From a61d525bf756ed54ca9f40e461b1e31227316b73 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 5 Jan 2023 11:50:13 -0600 Subject: [PATCH 08/99] tweaks for study --- rope/base/project.py | 1 + rope/base/utils/__init__.py | 3 ++- ropetest/objectinfertest.py | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/rope/base/project.py b/rope/base/project.py index 81e78d2d1..f0ab0ad48 100644 --- a/rope/base/project.py +++ b/rope/base/project.py @@ -347,6 +347,7 @@ def __init__(self, project): ) self.project.add_observer(rawobserver) + def get_files(self): if self.files is None: self.files = set() diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index c96c96428..526b9d060 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -61,7 +61,8 @@ def _decorator(func, message=message): message = "%s is deprecated" % func.__name__ def newfunc(*args, **kwds): - warnings.warn(message, DeprecationWarning, stacklevel=2) + if 0: ### + warnings.warn(message, DeprecationWarning, stacklevel=2) return func(*args, **kwds) return newfunc diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index a46a7c018..5cd28843b 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -5,10 +5,15 @@ from rope.base import libutils from ropetest import testutils +from leo.core import leoGlobals as g ### + class ObjectInferTest(unittest.TestCase): def setUp(self): super().setUp() + if self.id().endswith('test_simple_type_inferencing'): + print('ObjectInferTest.setUp', self.id()) + g.pdb() self.project = testutils.sample_project() def tearDown(self): @@ -21,9 +26,21 @@ class Sample(object): pass a_var = Sample() """) + g.pdb() # Same as import pdb; pdb.set_trace + + # scope is a GlobalScope. + # scope.pyobject is a PyModule. scope = libutils.get_string_scope(self.project, code) + + # scope["Sample"] is a DefinedName. + # scope["Sample"].pyobject is a PyClass. sample_class = scope["Sample"].get_object() + + # scope["a_var"] is an AssignedName. + # scope["a_var"].pyobject is an _Inferred. + # scope["a_var"].get_object() is a PyObject. a_var = scope["a_var"].get_object() + self.assertEqual(sample_class, a_var.get_type()) def test_simple_type_inferencing_classes_defined_in_holding_scope(self): From 15bf2b948a6e288845c2b6b3d5d8acafac7df814 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 5 Jan 2023 11:53:38 -0600 Subject: [PATCH 09/99] Blacken --- rope/base/project.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rope/base/project.py b/rope/base/project.py index f0ab0ad48..81e78d2d1 100644 --- a/rope/base/project.py +++ b/rope/base/project.py @@ -347,7 +347,6 @@ def __init__(self, project): ) self.project.add_observer(rawobserver) - def get_files(self): if self.files is None: self.files = set() From 2a312b99641bd861027f2a3a90d84aa6bf60139d Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 6 Jan 2023 07:49:30 -0600 Subject: [PATCH 10/99] Improve docstrings. Add annotations --- rope/base/libutils.py | 4 ++-- rope/base/pycore.py | 8 +++++++- ropetest/objectinfertest.py | 41 ++++++++++++++++++++++--------------- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/rope/base/libutils.py b/rope/base/libutils.py index f5b0ff461..25ae5e41a 100644 --- a/rope/base/libutils.py +++ b/rope/base/libutils.py @@ -81,7 +81,7 @@ def analyze_modules(project, task_handle=taskhandle.DEFAULT_TASK_HANDLE): def get_string_module(project, code, resource=None, force_errors=False): - """Returns a `PyObject` object for the given code + """Instantiates a `PyModule` object for the given code. If `force_errors` is `True`, `exceptions.ModuleSyntaxError` is raised if module has syntax errors. This overrides @@ -94,7 +94,7 @@ def get_string_module(project, code, resource=None, force_errors=False): def get_string_scope(project, code, resource=None): - """Returns a `Scope` object for the given code""" + """Instantiates a `Scope` object for the given code""" return get_string_module(project, code, resource).get_scope() diff --git a/rope/base/pycore.py b/rope/base/pycore.py index 0341312ae..9a9f59b1c 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -1,6 +1,8 @@ +from __future__ import annotations import bisect import contextlib import difflib +from typing import TYPE_CHECKING import warnings import rope.base.libutils @@ -11,6 +13,10 @@ import rope.base.resources from rope.base import builtins, exceptions, pyobjectsdef, stdmods, taskhandle, utils +if TYPE_CHECKING: + from rope.base.pyscopes import Scope + from rope.base.resources import Resource + class PyCore: def __init__(self, project): @@ -97,7 +103,7 @@ def get_string_module(self, code, resource=None, force_errors=False): return pyobjectsdef.PyModule(self, code, resource, force_errors=force_errors) @utils.deprecated("Use `libutils.get_string_scope` instead") - def get_string_scope(self, code, resource=None): + def get_string_scope(self, code: str, resource: Resource=None) -> Scope: """Returns a `Scope` object for the given code""" return rope.base.libutils.get_string_scope(code, resource) diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 5cd28843b..cda9bd58a 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -5,15 +5,17 @@ from rope.base import libutils from ropetest import testutils -from leo.core import leoGlobals as g ### - class ObjectInferTest(unittest.TestCase): def setUp(self): + """ + Init self.project to a new Project instance for this test, with default prefs. + self.project.fscommands manages temp files in a temp directory. + """ super().setUp() - if self.id().endswith('test_simple_type_inferencing'): - print('ObjectInferTest.setUp', self.id()) - g.pdb() + if 0: ### + if self.id().endswith('test_simple_type_inferencing'): + import pdb ; pdb.set_trace() self.project = testutils.sample_project() def tearDown(self): @@ -26,20 +28,27 @@ class Sample(object): pass a_var = Sample() """) - g.pdb() # Same as import pdb; pdb.set_trace - - # scope is a GlobalScope. - # scope.pyobject is a PyModule. + # setUp instantiates self.project to a Project instance. + + ### import pdb ; pdb.set_trace() ### + scope = libutils.get_string_scope(self.project, code) - - # scope["Sample"] is a DefinedName. - # scope["Sample"].pyobject is a PyClass. + # scope is a GlobalScope. It might be any subclass of Scope. + # scope.pyobject is a pyobjectsdef.PyModule. + sample_class = scope["Sample"].get_object() - - # scope["a_var"] is an AssignedName. - # scope["a_var"].pyobject is an _Inferred. - # scope["a_var"].get_object() is a PyObject. + # sample_class is a pyobjectsdef.PyClass ("::Sample" at 0x14035953520) + + # scope["Sample"] is a DefinedName. + # scope["Sample"].pyobject is a pyobjectsdef.PyClass. + a_var = scope["a_var"].get_object() + # a_var is a pyobjects.PyObject + # a_var.get_type() is a pyobjectsdef.PyClass ("::Sample" at 0x14035953520) + + # scope["a_var"] is an pynamesdef.AssignedName. + # scope["a_var"].pyobject is a pynames._Inferred. + # scope["a_var"].get_object() is a pyobjects.PyObject. self.assertEqual(sample_class, a_var.get_type()) From 1c06fc7d5ef58475ef137a1796b3897bee9c41bf Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 6 Jan 2023 08:28:44 -0600 Subject: [PATCH 11/99] Add traces to saveit decorator --- rope/base/utils/__init__.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 526b9d060..35a20cd89 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -2,6 +2,8 @@ import warnings +###print_flag = False ### + def saveit(func): """A decorator that caches the return value of a function""" @@ -9,7 +11,21 @@ def saveit(func): def _wrapper(self, *args, **kwds): if not hasattr(self, name): - setattr(self, name, func(self, *args, **kwds)) + if 1: ### + # global print_flag + # if not print_flag: + # print('') + # print_flag = True + print('') + val = func(self, *args, **kwds) + func_name = repr(func).replace('20}.{name:<20} {func_name[:i]}()") + from leo.core import leoGlobals as g ### + g.printObj(val, tag=f"{self.__class__.__name__}.{name} = {func_name[:i]}()") + setattr(self, name, val) + else: ### original. + setattr(self, name, func(self, *args, **kwds)) return getattr(self, name) return _wrapper From e7a38b962d7e4eb9ee3c7195aa6613c5ae5d75df Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 6 Jan 2023 09:47:45 -0600 Subject: [PATCH 12/99] Improve traces --- rope/base/utils/__init__.py | 24 ++++++++++++------------ ropetest/objectinfertest.py | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 35a20cd89..1bcb6fd70 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -2,7 +2,7 @@ import warnings -###print_flag = False ### +from leo.core import leoGlobals as g ### def saveit(func): """A decorator that caches the return value of a function""" @@ -11,18 +11,18 @@ def saveit(func): def _wrapper(self, *args, **kwds): if not hasattr(self, name): - if 1: ### - # global print_flag - # if not print_flag: - # print('') - # print_flag = True - print('') + if 0: ### val = func(self, *args, **kwds) - func_name = repr(func).replace('20}.{name:<20} {func_name[:i]}()") - from leo.core import leoGlobals as g ### - g.printObj(val, tag=f"{self.__class__.__name__}.{name} = {func_name[:i]}()") + func_name = repr(func) + if 0: # Brief func_name + func_name = func_name.replace('20}.{name:<20} = {func_name}") + else: # Verbose. + print('') + g.printObj(val, tag=f"{self.__class__.__name__}.{name} = {func_name}") setattr(self, name, val) else: ### original. setattr(self, name, func(self, *args, **kwds)) diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index cda9bd58a..cfa250901 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -12,6 +12,7 @@ def setUp(self): Init self.project to a new Project instance for this test, with default prefs. self.project.fscommands manages temp files in a temp directory. """ + ### print('') ### A hack, for the traces in saveit. super().setUp() if 0: ### if self.id().endswith('test_simple_type_inferencing'): From ea9c6752bcc15a3d3862da7572a10b1c7224ae3f Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 6 Jan 2023 09:57:35 -0600 Subject: [PATCH 13/99] Blacken. Suppress pylint warning about pdb. --- rope/base/pycore.py | 2 +- rope/base/utils/__init__.py | 15 ++++++++++----- ropetest/objectinfertest.py | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/rope/base/pycore.py b/rope/base/pycore.py index 9a9f59b1c..2f1e92212 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -103,7 +103,7 @@ def get_string_module(self, code, resource=None, force_errors=False): return pyobjectsdef.PyModule(self, code, resource, force_errors=force_errors) @utils.deprecated("Use `libutils.get_string_scope` instead") - def get_string_scope(self, code: str, resource: Resource=None) -> Scope: + def get_string_scope(self, code: str, resource: Resource = None) -> Scope: """Returns a `Scope` object for the given code""" return rope.base.libutils.get_string_scope(code, resource) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 1bcb6fd70..c47d6fd0c 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -4,6 +4,7 @@ from leo.core import leoGlobals as g ### + def saveit(func): """A decorator that caches the return value of a function""" @@ -15,14 +16,18 @@ def _wrapper(self, *args, **kwds): val = func(self, *args, **kwds) func_name = repr(func) if 0: # Brief func_name - func_name = func_name.replace('20}.{name:<20} = {func_name}") + print( + f"saveit: {self.__class__.__name__:>20}.{name:<20} = {func_name}" + ) else: # Verbose. - print('') - g.printObj(val, tag=f"{self.__class__.__name__}.{name} = {func_name}") + print("") + g.printObj( + val, tag=f"{self.__class__.__name__}.{name} = {func_name}" + ) setattr(self, name, val) else: ### original. setattr(self, name, func(self, *args, **kwds)) diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index cfa250901..2ffd57bd8 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -16,7 +16,7 @@ def setUp(self): super().setUp() if 0: ### if self.id().endswith('test_simple_type_inferencing'): - import pdb ; pdb.set_trace() + import pdb ; pdb.set_trace() # pylint: disable=forgotten-debug-statement self.project = testutils.sample_project() def tearDown(self): From d7cae095f0251ad9b8ab7958ffbbd35200e324e3 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 6 Jan 2023 16:12:34 -0600 Subject: [PATCH 14/99] Add print statement --- rope/base/utils/__init__.py | 2 +- ropetest/objectinfertest.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index c47d6fd0c..06ff9bb64 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -2,7 +2,7 @@ import warnings -from leo.core import leoGlobals as g ### +from leo.core import leoGlobals as g ; assert g ### def saveit(func): diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 2ffd57bd8..08c3656f4 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -12,9 +12,10 @@ def setUp(self): Init self.project to a new Project instance for this test, with default prefs. self.project.fscommands manages temp files in a temp directory. """ - ### print('') ### A hack, for the traces in saveit. + if 0: + print('') # For single tests. super().setUp() - if 0: ### + if 0: if self.id().endswith('test_simple_type_inferencing'): import pdb ; pdb.set_trace() # pylint: disable=forgotten-debug-statement self.project = testutils.sample_project() From fb5dec3127fff1f43a2b5ca31393063803d50017 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 6 Jan 2023 16:15:45 -0600 Subject: [PATCH 15/99] rename func to class_name --- rope/base/utils/__init__.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 06ff9bb64..67ce7f1b1 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -2,19 +2,21 @@ import warnings -from leo.core import leoGlobals as g ; assert g ### +from leo.core import leoGlobals as g +assert g ### -def saveit(func): + +def inject_object(class_name): """A decorator that caches the return value of a function""" - name = "_" + func.__name__ + name = "_" + class_name.__name__ def _wrapper(self, *args, **kwds): if not hasattr(self, name): - if 0: ### - val = func(self, *args, **kwds) - func_name = repr(func) + if 0: # Tracing version. + val = class_name(self, *args, **kwds) + func_name = repr(class_name) if 0: # Brief func_name func_name = func_name.replace(" Date: Fri, 6 Jan 2023 16:26:24 -0600 Subject: [PATCH 16/99] Tweaks --- rope/base/utils/__init__.py | 36 ++++++++++++++++++------------------ ropetest/objectinfertest.py | 4 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 67ce7f1b1..2927a44b5 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -8,31 +8,31 @@ def inject_object(class_name): - """A decorator that caches the return value of a function""" + """ + A decorator that instantiates an instance of the class whose name is given + and injects that + + """ + # """A decorator that caches the return value of a function""" name = "_" + class_name.__name__ def _wrapper(self, *args, **kwds): if not hasattr(self, name): - if 0: # Tracing version. - val = class_name(self, *args, **kwds) + obj = class_name(self, *args, **kwds) + if 1: # Tracing version. + self_name = self.__class__.__name__ func_name = repr(class_name) - if 0: # Brief func_name - func_name = func_name.replace("20}.{name:<20} = {func_name}" - ) + if 1: # Brief func_name + temp_name = func_name.replace("15}.{name:<20} = {func_name}") else: # Verbose. - print("") - g.printObj( - val, tag=f"{self.__class__.__name__}.{name} = {func_name}" - ) - setattr(self, name, val) - else: # Original. - setattr(self, name, class_name(self, *args, **kwds)) + g.printObj(obj, tag=f"{self_name}.{name} = {func_name}") + setattr(self, name, obj) + # Original. + # setattr(self, name, class_name(self, *args, **kwds)) return getattr(self, name) return _wrapper diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 08c3656f4..3120d2c1a 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -12,8 +12,8 @@ def setUp(self): Init self.project to a new Project instance for this test, with default prefs. self.project.fscommands manages temp files in a temp directory. """ - if 0: - print('') # For single tests. + if 1: + print('') # For single tests. Does not affect full-test-r script. super().setUp() if 0: if self.id().endswith('test_simple_type_inferencing'): From 922362944f08c2b545d6505b85dcea93da4b3105 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 6 Jan 2023 17:11:13 -0600 Subject: [PATCH 17/99] Improve docstring and traces --- rope/base/utils/__init__.py | 49 ++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 2927a44b5..1c4ea682e 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -7,39 +7,42 @@ assert g ### -def inject_object(class_name): +def inject(func): """ - A decorator that instantiates an instance of the class whose name is given - and injects that - + func is a function that instantiates an object. + + This decorator injects the object as an ivar of self. + The ivars's name is "_" + func.__name__. + """ # """A decorator that caches the return value of a function""" + tag = "@inject" + ivar_name = "_" + func.__name__ - name = "_" + class_name.__name__ - - def _wrapper(self, *args, **kwds): - if not hasattr(self, name): - obj = class_name(self, *args, **kwds) + def _wrapper(self, *args, **kwargs): + if not hasattr(self, ivar_name): + # Instantiate the object. + obj = func(self, *args, **kwargs) if 1: # Tracing version. - self_name = self.__class__.__name__ - func_name = repr(class_name) - if 1: # Brief func_name - temp_name = func_name.replace("15}.{name:<20} = {func_name}") - else: # Verbose. - g.printObj(obj, tag=f"{self_name}.{name} = {func_name}") - setattr(self, name, obj) + injected_name = f"{self.__class__.__name__}.{ivar_name}" + func_s = repr(func).replace("30} = {description}") + else: + print("") + g.printObj(obj, tag=f"{tag} ivar: {injected_name} = {description}") + setattr(self, ivar_name, obj) # Original. - # setattr(self, name, class_name(self, *args, **kwds)) - return getattr(self, name) + # setattr(self, ivar_name, func(self, *args, **kwds)) + return getattr(self, ivar_name) return _wrapper -cacheit = inject_object -saveit = inject_object +cacheit = inject +saveit = inject def prevent_recursion(default): From 15c55e89e0c70086f675d34b86b16c6278361d93 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 6 Jan 2023 17:42:25 -0600 Subject: [PATCH 18/99] Improve docstring. Separate the trace and non-tracing versions of _wrapper --- rope/base/utils/__init__.py | 64 +++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 1c4ea682e..bc3f63767 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -9,34 +9,50 @@ def inject(func): """ - func is a function that instantiates an object. + A decorator that injects ivars (in self) whose values are singleton objects. - This decorator injects the object as an ivar of self. - The ivars's name is "_" + func.__name__. + :param func: A function/method that instantiates an object. + + :return: getattr(self, ivar_name), creating the ivar as necessary, + where ivar_name = f"_{func.__name__}" """ # """A decorator that caches the return value of a function""" - tag = "@inject" - ivar_name = "_" + func.__name__ - - def _wrapper(self, *args, **kwargs): - if not hasattr(self, ivar_name): - # Instantiate the object. - obj = func(self, *args, **kwargs) - if 1: # Tracing version. - injected_name = f"{self.__class__.__name__}.{ivar_name}" - func_s = repr(func).replace("30} = {description}") - else: - print("") - g.printObj(obj, tag=f"{tag} ivar: {injected_name} = {description}") - setattr(self, ivar_name, obj) - # Original. - # setattr(self, ivar_name, func(self, *args, **kwds)) - return getattr(self, ivar_name) + ivar_name = f"_{func.__name__}" + + if 1: # Original version: + + def _wrapper(self, *args, **kwargs): + if not hasattr(self, ivar_name): + # Instantiate the singleton object. + obj = func(self, *args, **kwargs) + setattr(self, ivar_name, obj) + # Return the value of the ivar. + return getattr(self, ivar_name) + + else: + + def _wrapper(self, *args, **kwargs): + tag = "@inject" + if not hasattr(self, ivar_name): + # Instantiate the object. + obj = func(self, *args, **kwargs) + if 1: # Tracing version. + injected_name = f"{self.__class__.__name__}.{ivar_name}" + func_s = repr(func).replace("30} = {description}") + else: + print("") + g.printObj( + obj, tag=f"{tag} ivar: {injected_name} = {description}" + ) + setattr(self, ivar_name, obj) + # Original. + # setattr(self, ivar_name, func(self, *args, **kwds)) + return getattr(self, ivar_name) return _wrapper From 353898dd2ce7a28fd391b0be4e712f39e9e7b141 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 6 Jan 2023 17:49:18 -0600 Subject: [PATCH 19/99] Tweak docstring --- rope/base/utils/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index bc3f63767..acd730483 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -9,12 +9,15 @@ def inject(func): """ - A decorator that injects ivars (in self) whose values are singleton objects. + A decorator that injects a singleton ivar in self. :param func: A function/method that instantiates an object. + + The ivar's name (ivar_name) is f"_{func.__name__}". + + The decorator creates the ivar if it does not exist. - :return: getattr(self, ivar_name), creating the ivar as necessary, - where ivar_name = f"_{func.__name__}" + :return: getattr(self, ivar_name), the value of the ivar. """ # """A decorator that caches the return value of a function""" From 7c35a7058b07c0a58765bfff3e2494dd2c55eb5b Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 6 Jan 2023 17:50:55 -0600 Subject: [PATCH 20/99] Another go at the docstring --- rope/base/utils/__init__.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index acd730483..b0b3fb008 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -9,14 +9,13 @@ def inject(func): """ - A decorator that injects a singleton ivar in self. + A decorator that injects a singleton ivar (in self) if the ivar does + not already exist. - :param func: A function/method that instantiates an object. - The ivar's name (ivar_name) is f"_{func.__name__}". - - The decorator creates the ivar if it does not exist. + :param func: A function/method that instantiates an object. + :return: getattr(self, ivar_name), the value of the ivar. """ From 0011f3d15f908165d7127f9fa0dcabd5b3172cfe Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 27 Jan 2023 01:42:23 -0600 Subject: [PATCH 21/99] traces --- rope/base/utils/__init__.py | 4 ++-- ropetest/objectinfertest.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index b0b3fb008..e962e5086 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -15,7 +15,7 @@ def inject(func): The ivar's name (ivar_name) is f"_{func.__name__}". :param func: A function/method that instantiates an object. - + :return: getattr(self, ivar_name), the value of the ivar. """ @@ -44,7 +44,7 @@ def _wrapper(self, *args, **kwargs): func_s = repr(func).replace("30} = {description}") else: print("") diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 3120d2c1a..f6270cbd2 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -13,7 +13,7 @@ def setUp(self): self.project.fscommands manages temp files in a temp directory. """ if 1: - print('') # For single tests. Does not affect full-test-r script. + print('') # For single tests. Does not affect the test-r or full-test-r scripts. super().setUp() if 0: if self.id().endswith('test_simple_type_inferencing'): @@ -32,7 +32,7 @@ class Sample(object): """) # setUp instantiates self.project to a Project instance. - ### import pdb ; pdb.set_trace() ### + import pdb ; pdb.set_trace() ### scope = libutils.get_string_scope(self.project, code) # scope is a GlobalScope. It might be any subclass of Scope. From d24dc8b7abdcefea9dcb20039168e8ffd469f225 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 27 Jan 2023 14:48:38 -0600 Subject: [PATCH 22/99] Improve headlines --- ropetest/objectinfertest.py | 50 +++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index f6270cbd2..06ba1a4aa 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -5,6 +5,8 @@ from rope.base import libutils from ropetest import testutils +from leo.core import leoGlobals as g ### + class ObjectInferTest(unittest.TestCase): def setUp(self): @@ -15,9 +17,6 @@ def setUp(self): if 1: print('') # For single tests. Does not affect the test-r or full-test-r scripts. super().setUp() - if 0: - if self.id().endswith('test_simple_type_inferencing'): - import pdb ; pdb.set_trace() # pylint: disable=forgotten-debug-statement self.project = testutils.sample_project() def tearDown(self): @@ -30,27 +29,40 @@ class Sample(object): pass a_var = Sample() """) - # setUp instantiates self.project to a Project instance. - - import pdb ; pdb.set_trace() ### - - scope = libutils.get_string_scope(self.project, code) - # scope is a GlobalScope. It might be any subclass of Scope. - # scope.pyobject is a pyobjectsdef.PyModule. + + # 1. setUp creates self.project. + + # setUp instantiates self.project to a Project instance. + # self.project = testutils.sample_project() + + # 2. get_string_scope sets self.scope to the scope of the test string. + + # Sets self.scope to pyobjectsdef.PyModule(project.pycore, code, ...) + # (code is the test string, defined above.) + + # Instantiating the pyobjectsdef.PyModule does all the work!!! + scope = libutils.get_string_scope(self.project, code) + + # scope is a GlobalScope. It might be any subclass of Scope. + # scope.pyobject is a pyobjectsdef.PyModule. sample_class = scope["Sample"].get_object() - # sample_class is a pyobjectsdef.PyClass ("::Sample" at 0x14035953520) - - # scope["Sample"] is a DefinedName. - # scope["Sample"].pyobject is a pyobjectsdef.PyClass. + + # sample_class is a pyobjectsdef.PyClass ("::Sample" at ...) + # scope["Sample"] is a DefinedName. + # scope["Sample"].pyobject is a pyobjectsdef.PyClass. a_var = scope["a_var"].get_object() - # a_var is a pyobjects.PyObject - # a_var.get_type() is a pyobjectsdef.PyClass ("::Sample" at 0x14035953520) + + # a_var is a pyobjects.PyObject + # a_var.get_type() is a pyobjectsdef.PyClass ("::Sample" at ...) - # scope["a_var"] is an pynamesdef.AssignedName. - # scope["a_var"].pyobject is a pynames._Inferred. - # scope["a_var"].get_object() is a pyobjects.PyObject. + # scope["a_var"] is an pynamesdef.AssignedName. + # scope["a_var"].pyobject is a pynames._Inferred. + # scope["a_var"].get_object() is a pyobjects.PyObject. + + print(f"\nsample_class: {sample_class}") + import pdb ; pdb.set_trace() ### self.assertEqual(sample_class, a_var.get_type()) From 981b7984c3a2adbee26c3c0946d59841851a069c Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sat, 28 Jan 2023 08:53:38 -0600 Subject: [PATCH 23/99] Add the g.trace_ctors pattern --- rope/base/pynames.py | 11 ++++++++++ rope/base/pyobjects.py | 27 ++++++++++++++++++++++-- rope/base/pyobjectsdef.py | 5 +++++ ropetest/objectinfertest.py | 42 +++++++++++++++++++++++++++++++++---- 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 3febd2197..f934f77c0 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -10,6 +10,7 @@ from rope.base import pyobjectsdef +from leo.core import leoGlobals as g ### class PyName: """References to `PyObject` inside python programs""" @@ -187,7 +188,17 @@ def get_definition_location(self): def _get_concluded_data(module): if module is None: + g.trace('(*** pynames function): instantiate') ### return rope.base.pyobjects._ConcludedData() + if 0: ### + # Callers... + # test_simple_type_inferencing,__getitem__,get_name,__getitem__, + # get_attribute,newfunc,_get_structural_attributes,_create_structural_attributes, + # visit,_Assign,visit,_Assign,visit,_Name,_assigned,_assigned,__init__ + print('') + g.trace('(*** pynames function): return module._get_concluded_data') + g.trace(g.callers(17)) + g.trace(module._ekr_dump_concluded_data()) return module._get_concluded_data() diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 4c9fadf27..9511e64c8 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -2,6 +2,8 @@ from rope.base import ast, exceptions, utils +from leo.core import leoGlobals as g ### + class PyObject: def __init__(self, type_): @@ -171,6 +173,8 @@ def __init__(self, pycore, ast_node, parent): self.concluded_attributes = self.get_module()._get_concluded_data() self.attributes = self.get_module()._get_concluded_data() self.defineds = None + if getattr(g, 'trace_ctors', None): ### + g.trace(f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", g.callers()) def __repr__(self): return '<{}.{} "{}" at {}>'.format( @@ -289,16 +293,22 @@ def _invalidate(self): self.data = None def __str__(self): - return "<" + str(self.data) + ">" + return "pyobjects._ConcludedData<" + str(self.data) + ">" + + ### + def _ekr_dump(self): + + g.printObj(self.data, tag=f"***** pyobjects._ConcludedData: {id(self)}") class _PyModule(PyDefinedObject, AbstractModule): def __init__(self, pycore, ast_node, resource): self.resource = resource self.concluded_data = [] AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) - + if getattr(g, 'trace_ctors', None): ### + g.trace(f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", g.callers()) @property def absolute_name(self) -> str: return self.get_name() @@ -316,6 +326,19 @@ def get_resource(self): return self.resource + def _ekr_dump_concluded_data(self): + + g.trace('(pyobjects._PyModule._ekr_dump_concluded_data)') + tag = self.get_name() + try: + for i, z in enumerate(self.concluded_data): + g.printObj(f"{i:3} {z!s}", tag=tag) + # z._ekr_dump() + except TypeError: + z = self.concluded_data + g.printObj(f"{z!s}", tag=tag) + # z._ekr_dump() + class PyModule(_PyModule): pass diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 2bb374233..8976f8326 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -15,6 +15,7 @@ utils, ) +from leo.core import leoGlobals as g ### class PyFunction(pyobjects.PyFunction): def __init__(self, pycore, ast_node, parent): @@ -133,6 +134,8 @@ def __init__(self, pycore, ast_node, parent): rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent) self.parent = parent self._superclasses = self.get_module()._get_concluded_data() + if getattr(g, 'trace_ctors', None): ### + g.trace(f"{g.get_ctor_name(self, __file__)} {' ':14}", g.callers()) def get_superclasses(self): if self._superclasses.get() is None: @@ -182,6 +185,8 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.star_imports = [] self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) + if getattr(g, 'trace_ctors', None): ### + g.trace(f"{g.get_ctor_name(self, __file__)} {' ':14}", g.callers()) super().__init__(pycore, node, resource) def _init_source(self, pycore, source_code, resource): diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 06ba1a4aa..d6dbba51c 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -30,6 +30,28 @@ class Sample(object): a_var = Sample() """) + # Inject g attributes to support this pattern: + # + # if getattr(g, 'trace_ctors', None): + # g.trace( + # f"{g.get_ctor_name(self, __file__)} " + # f"{ast_node.__class__.__name__:14}", # or f"({' ':14'}" + # g.callers()) + + def get_ctor_name(self, file_name): + class_name = self.__class__.__name__ + module_name = g.shortFileName(file_name).replace('.py', '') + combined_name = f"{module_name}.{class_name}" + return f"{combined_name:>25}" + + g.trace_ctors = True # True: Enable tracing in ctors. + g.get_ctor_name = get_ctor_name # Inject the formatting function. + + def banner(s): + if 1: print(f"\n===== {s}\n") + + banner('after setUp') + # 1. setUp creates self.project. # setUp instantiates self.project to a Project instance. @@ -40,14 +62,26 @@ class Sample(object): # Sets self.scope to pyobjectsdef.PyModule(project.pycore, code, ...) # (code is the test string, defined above.) - # Instantiating the pyobjectsdef.PyModule does all the work!!! - scope = libutils.get_string_scope(self.project, code) + # ??? Instantiating the pyobjectsdef.PyModule does all the work ??? + + # PyDefinedObject.__init__ calls: + + # self.concluded_attributes = self.get_module()._get_concluded_data() + # self.attributes = self.get_module()._get_concluded_data() + + # But all attributes are empty for this test. + + scope = libutils.get_string_scope(self.project, code) + + banner('after get_string_scope') # scope is a GlobalScope. It might be any subclass of Scope. # scope.pyobject is a pyobjectsdef.PyModule. sample_class = scope["Sample"].get_object() + banner('after sample_class = scope["Sample"].get_object()') + # sample_class is a pyobjectsdef.PyClass ("::Sample" at ...) # scope["Sample"] is a DefinedName. # scope["Sample"].pyobject is a pyobjectsdef.PyClass. @@ -61,8 +95,8 @@ class Sample(object): # scope["a_var"].pyobject is a pynames._Inferred. # scope["a_var"].get_object() is a pyobjects.PyObject. - print(f"\nsample_class: {sample_class}") - import pdb ; pdb.set_trace() ### + print(f"sample_class: {sample_class}") + ### import pdb ; pdb.set_trace() ### self.assertEqual(sample_class, a_var.get_type()) From 348d8393f0738c0ae33abf4641d6f2d4a5297dde Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sat, 28 Jan 2023 16:41:58 -0600 Subject: [PATCH 24/99] Add more traces --- rope/base/pyobjectsdef.py | 6 ++++-- rope/base/pyscopes.py | 4 ++++ ropetest/objectinfertest.py | 30 +++++++++++++++++------------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 8976f8326..c45e8b3a3 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -588,8 +588,10 @@ def _get_pyobject(self, node): class _GlobalVisitor(_ScopeVisitor): - def __init__(self, pycore, owner_object): - super().__init__(pycore, owner_object) + pass ### + ### + # def __init__(self, pycore, owner_object): + # super().__init__(pycore, owner_object) class _ClassVisitor(_ScopeVisitor): diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index 565541903..08fc83bfe 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -2,13 +2,17 @@ from rope.base import ast, codeanalyze, exceptions, pynames, utils from rope.refactor import patchedast +from leo.core import leoGlobals as g ### +assert g ### class Scope: + def __init__(self, pycore, pyobject, parent_scope): self.pycore = pycore self.pyobject = pyobject self.parent = parent_scope + def get_names(self): """Return the names defined or imported in this scope""" return self.pyobject.get_attributes() diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index d6dbba51c..a28318a39 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -30,25 +30,22 @@ class Sample(object): a_var = Sample() """) - # Inject g attributes to support this pattern: - # - # if getattr(g, 'trace_ctors', None): - # g.trace( - # f"{g.get_ctor_name(self, __file__)} " - # f"{ast_node.__class__.__name__:14}", # or f"({' ':14'}" - # g.callers()) - + trace = False # Set to False when running all tests. + def get_ctor_name(self, file_name): + """Return .:>20""" class_name = self.__class__.__name__ module_name = g.shortFileName(file_name).replace('.py', '') combined_name = f"{module_name}.{class_name}" return f"{combined_name:>25}" - g.trace_ctors = True # True: Enable tracing in ctors. - g.get_ctor_name = get_ctor_name # Inject the formatting function. + if trace: + g.trace_ctors = True # True: Enable tracing in ctors. + g.get_ctor_name = get_ctor_name # Inject the formatting function. def banner(s): - if 1: print(f"\n===== {s}\n") + if trace: + print(f"\n===== {s}\n") banner('after setUp') @@ -77,11 +74,19 @@ def banner(s): # scope is a GlobalScope. It might be any subclass of Scope. # scope.pyobject is a pyobjectsdef.PyModule. + + if trace: g.trace('*** scope.pyobject', scope.pyobject) + # *** Calling scope["Sample"] (via _ScopeVisitor._ClassDef) + # instantiates pyobjects.PyClass *and* pyobjectsdef.PyClass. + # (Because pyobjectsDef.PyClass is a subclass of pyobjects.PyClass.) + # scope["Sample"] is a pynamesdef.DefinedName. + sample_class = scope["Sample"].get_object() banner('after sample_class = scope["Sample"].get_object()') + # sample_class is a pyobjectsdef.PyClass ("::Sample" at ...) # scope["Sample"] is a DefinedName. # scope["Sample"].pyobject is a pyobjectsdef.PyClass. @@ -95,8 +100,7 @@ def banner(s): # scope["a_var"].pyobject is a pynames._Inferred. # scope["a_var"].get_object() is a pyobjects.PyObject. - print(f"sample_class: {sample_class}") - ### import pdb ; pdb.set_trace() ### + if trace: print(f"sample_class: {sample_class}") self.assertEqual(sample_class, a_var.get_type()) From b8171226362a80863b477fc464cc131c114f70dd Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sat, 28 Jan 2023 17:47:33 -0600 Subject: [PATCH 25/99] Blacken several files. Let's hope rope's test actions succeed this time --- rope/base/pynames.py | 7 ++++--- rope/base/pyobjects.py | 26 +++++++++++++++++--------- rope/base/pyobjectsdef.py | 7 ++++--- rope/base/pyscopes.py | 4 ++-- ropetest/objectinfertest.py | 2 +- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index f934f77c0..8ed63dbbf 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -12,6 +12,7 @@ from leo.core import leoGlobals as g ### + class PyName: """References to `PyObject` inside python programs""" @@ -188,15 +189,15 @@ def get_definition_location(self): def _get_concluded_data(module): if module is None: - g.trace('(*** pynames function): instantiate') ### + g.trace("(*** pynames function): instantiate") ### return rope.base.pyobjects._ConcludedData() if 0: ### # Callers... # test_simple_type_inferencing,__getitem__,get_name,__getitem__, # get_attribute,newfunc,_get_structural_attributes,_create_structural_attributes, # visit,_Assign,visit,_Assign,visit,_Name,_assigned,_assigned,__init__ - print('') - g.trace('(*** pynames function): return module._get_concluded_data') + print("") + g.trace("(*** pynames function): return module._get_concluded_data") g.trace(g.callers(17)) g.trace(module._ekr_dump_concluded_data()) return module._get_concluded_data() diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 9511e64c8..fd097cf77 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -173,8 +173,11 @@ def __init__(self, pycore, ast_node, parent): self.concluded_attributes = self.get_module()._get_concluded_data() self.attributes = self.get_module()._get_concluded_data() self.defineds = None - if getattr(g, 'trace_ctors', None): ### - g.trace(f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", g.callers()) + if getattr(g, "trace_ctors", None): ### + g.trace( + f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", + g.callers(), + ) def __repr__(self): return '<{}.{} "{}" at {}>'.format( @@ -294,21 +297,26 @@ def _invalidate(self): def __str__(self): return "pyobjects._ConcludedData<" + str(self.data) + ">" - - ### + ### def _ekr_dump(self): - + g.printObj(self.data, tag=f"***** pyobjects._ConcludedData: {id(self)}") + + class _PyModule(PyDefinedObject, AbstractModule): def __init__(self, pycore, ast_node, resource): self.resource = resource self.concluded_data = [] AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) - if getattr(g, 'trace_ctors', None): ### - g.trace(f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", g.callers()) + if getattr(g, "trace_ctors", None): ### + g.trace( + f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", + g.callers(), + ) + @property def absolute_name(self) -> str: return self.get_name() @@ -325,10 +333,9 @@ def _forget_concluded_data(self): def get_resource(self): return self.resource - def _ekr_dump_concluded_data(self): - g.trace('(pyobjects._PyModule._ekr_dump_concluded_data)') + g.trace("(pyobjects._PyModule._ekr_dump_concluded_data)") tag = self.get_name() try: for i, z in enumerate(self.concluded_data): @@ -339,6 +346,7 @@ def _ekr_dump_concluded_data(self): g.printObj(f"{z!s}", tag=tag) # z._ekr_dump() + class PyModule(_PyModule): pass diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index c45e8b3a3..8c5dbe716 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -17,6 +17,7 @@ from leo.core import leoGlobals as g ### + class PyFunction(pyobjects.PyFunction): def __init__(self, pycore, ast_node, parent): rope.base.pyobjects.AbstractFunction.__init__(self) @@ -134,7 +135,7 @@ def __init__(self, pycore, ast_node, parent): rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent) self.parent = parent self._superclasses = self.get_module()._get_concluded_data() - if getattr(g, 'trace_ctors', None): ### + if getattr(g, "trace_ctors", None): ### g.trace(f"{g.get_ctor_name(self, __file__)} {' ':14}", g.callers()) def get_superclasses(self): @@ -185,7 +186,7 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.star_imports = [] self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) - if getattr(g, 'trace_ctors', None): ### + if getattr(g, "trace_ctors", None): ### g.trace(f"{g.get_ctor_name(self, __file__)} {' ':14}", g.callers()) super().__init__(pycore, node, resource) @@ -591,7 +592,7 @@ class _GlobalVisitor(_ScopeVisitor): pass ### ### # def __init__(self, pycore, owner_object): - # super().__init__(pycore, owner_object) + # super().__init__(pycore, owner_object) class _ClassVisitor(_ScopeVisitor): diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index 08fc83bfe..6fbece1db 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -3,16 +3,16 @@ from rope.refactor import patchedast from leo.core import leoGlobals as g ### + assert g ### -class Scope: +class Scope: def __init__(self, pycore, pyobject, parent_scope): self.pycore = pycore self.pyobject = pyobject self.parent = parent_scope - def get_names(self): """Return the names defined or imported in this scope""" return self.pyobject.get_attributes() diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index a28318a39..8ff2a191f 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -30,7 +30,7 @@ class Sample(object): a_var = Sample() """) - trace = False # Set to False when running all tests. + trace = True # Set to False when running all tests. def get_ctor_name(self, file_name): """Return .:>20""" From 21369949410288a31cece9dd0ad4a6a3a433c1ef Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 29 Jan 2023 02:05:47 -0600 Subject: [PATCH 26/99] Add rope.base.leoGlobals so checkin tasks have a chance of passing --- rope/base/leoGlobals.py | 227 ++++++++++++++++++++++++++++++++++++ rope/base/pynames.py | 4 +- rope/base/pyobjects.py | 4 +- rope/base/pyobjectsdef.py | 4 +- rope/base/pyscopes.py | 2 +- rope/base/utils/__init__.py | 3 +- ropetest/objectinfertest.py | 14 +-- 7 files changed, 241 insertions(+), 17 deletions(-) create mode 100644 rope/base/leoGlobals.py diff --git a/rope/base/leoGlobals.py b/rope/base/leoGlobals.py new file mode 100644 index 000000000..4797be1c1 --- /dev/null +++ b/rope/base/leoGlobals.py @@ -0,0 +1,227 @@ +""" +Tracing and debugging functions from Leo. + +Duplicated here so that Rope's commit checks won't fail. +""" + +# from __future__ import annotations +import os +import sys +from typing import Any, Dict, List + + +def _callerName(n: int) -> str: + try: + # get the function name from the call stack. + f1 = sys._getframe(n) # The stack frame, n levels up. + code1 = f1.f_code # The code object + locals_ = f1.f_locals # The local namespace. + name = code1.co_name + # sfn = shortFilename(code1.co_filename) # The file name. + # line = code1.co_firstlineno + obj = locals_.get("self") + if obj and name == "__init__": + return f"{obj.__class__.__name__}.{name}" + return name + except ValueError: + # The stack is not deep enough OR + # sys._getframe does not exist on this platform. + return "" + except Exception: + return "" # "" + + +def caller(i: int = 1) -> str: + """Return the caller name i levels up the stack.""" + return callers(i + 1).split(",")[0] + + +def callers(n: int = 4) -> str: + """ + Return a string containing a comma-separated list of the calling + function's callers. + """ + # Be careful to call _callerName with smaller values of i first: + # sys._getframe throws ValueError if there are less than i entries. + i, result = 3, [] + while 1: + s = _callerName(n=i) + if s: + result.append(s) + if not s or len(result) >= n: + break + i += 1 + return ",".join(reversed(result)) + + +def callers_list(n: int = 4) -> List[str]: + """ + Return a string containing a comma-separated list of the calling + function's callers. + """ + # Be careful to call _callerName with smaller values of i first: + # sys._getframe throws ValueError if there are less than i entries. + i, result = 3, [] + while 1: + s = _callerName(n=i) + if s: + result.append(s) + if not s or len(result) >= n: + break + i += 1 + return list(reversed(result)) + + +def get_ctor_name(self, file_name, width=25): + """Return .:>20""" + class_name = self.__class__.__name__ + module_name = shortFileName(file_name).replace(".py", "") + combined_name = f"{module_name}.{class_name}" + padding = " " * max(0, 25 - len(combined_name)) + return f"{padding}{combined_name}" + + +def plural(obj: Any) -> str: + """Return "s" or "" depending on n.""" + if isinstance(obj, (list, tuple, str)): + n = len(obj) + else: + n = obj + return "" if n == 1 else "s" + + +def printObj(obj: Any, indent: str = "", tag: str = None) -> None: + """Pretty print any Python object""" + print(objToString(obj, indent=indent, tag=tag)) + + +def objToString( + obj: Any, indent: str = "", tag: str = "", concise: bool = False +) -> str: + """ + Pretty print any Python object to a string. + + concise=False: (Legacy) return a detailed string. + concise=True: Return a summary string. + """ + if tag: + print(tag.strip()) + if concise: + r = repr(obj) + if obj is None: + return f"{indent}None" + if isinstance(obj, dict): + return f"{indent}dict: {len(obj.keys())} keys" + if isinstance(obj, list): + return f"{indent}list: {len(obj)} items plural(len(obj))" + if isinstance(obj, tuple): + return f"{indent}tuple: {len(obj)} item{plural(len(obj))}" + if "method" in r: + return f"{indent}method: {obj.__name__}" + if "class" in r: + return f"{indent}class" + if "module" in r: + return f"{indent}module" + return f"{indent}object: {obj!r}" + + # concise = False + if isinstance(obj, dict): + return dictToString(obj, indent=indent) + if isinstance(obj, list): + return listToString(obj, indent=indent) + if isinstance(obj, tuple): + return tupleToString(obj, indent=indent) + if isinstance(obj, str): + # Print multi-line strings as lists. + lines = splitLines(obj) + if len(lines) > 1: + return listToString(lines, indent=indent) + return f"{indent} {obj!r}" + + +def dictToString(d: Dict[str, str], indent: str = "", tag: str = None) -> str: + """Pretty print a Python dict to a string.""" + # pylint: disable=unnecessary-lambda + if not d: + return "{}" + result = ["{\n"] + indent2 = indent + " " * 4 + n = 2 + len(indent) + max([len(repr(z)) for z in d.keys()]) + for i, key in enumerate(sorted(d, key=lambda z: repr(z))): + pad = " " * max(0, (n - len(repr(key)))) + result.append(f"{pad}{key}:") + result.append(objToString(d.get(key), indent=indent2)) + if i + 1 < len(d.keys()): + result.append(",") + result.append("\n") + result.append(indent + "}") + s = "".join(result) + return f"{tag}...\n{s}\n" if tag else s + + +def listToString(obj: Any, indent: str = "", tag: str = None) -> str: + """Pretty print a Python list to a string.""" + if not obj: + return indent + "[]" + result = [indent, "["] + indent2 = indent + " " * 4 + # I prefer not to compress lists. + for i, obj2 in enumerate(obj): + result.append("\n" + indent2) + result.append(objToString(obj2, indent=indent2)) + if i + 1 < len(obj) > 1: + result.append(",") + else: + result.append("\n" + indent) + result.append("]") + s = "".join(result) + return f"{tag}...\n{s}\n" if tag else s + + +def tupleToString(obj: Any, indent: str = "", tag: str = None) -> str: + """Pretty print a Python tuple to a string.""" + if not obj: + return "()," + result = ["("] + indent2 = indent + " " * 4 + for i, obj2 in enumerate(obj): + if len(obj) > 1: + result.append("\n" + indent2) + result.append(objToString(obj2, indent=indent2)) + if len(obj) == 1 or i + 1 < len(obj): + result.append(",") + elif len(obj) > 1: + result.append("\n" + indent) + result.append(")") + s = "".join(result) + return f"{tag}...\n{s}\n" if tag else s + + +def shortFileName(fileName: str, n: int = None) -> str: + """Return the base name of a path.""" + if n is not None: + trace('"n" keyword argument is no longer used') + return os.path.basename(fileName) if fileName else "" + + +shortFilename = shortFileName + + +def splitLines(s: str) -> List[str]: + """ + Split s into lines, preserving the number of lines and + the endings of all lines, including the last line. + """ + return s.splitlines(True) if s else [] # This is a Python string function! + + +splitlines = splitLines + + +def trace(*args: Any) -> None: + """Print the name of the calling function followed by all the args.""" + name = _callerName(2) + if name.endswith(".pyc"): + name = name[:-1] + args = "".join(str(z) for z in args) + print(f"{name} {args}") diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 8ed63dbbf..f33e9166e 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -10,7 +10,9 @@ from rope.base import pyobjectsdef -from leo.core import leoGlobals as g ### +from rope.base import leoGlobals as g ### + +assert g ### class PyName: diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index fd097cf77..239276684 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -2,7 +2,9 @@ from rope.base import ast, exceptions, utils -from leo.core import leoGlobals as g ### +from rope.base import leoGlobals as g ### + +assert g ### class PyObject: diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 8c5dbe716..08841adb7 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -15,7 +15,9 @@ utils, ) -from leo.core import leoGlobals as g ### +from rope.base import leoGlobals as g ### + +assert g ### class PyFunction(pyobjects.PyFunction): diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index 6fbece1db..b97b8bf51 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -2,7 +2,7 @@ from rope.base import ast, codeanalyze, exceptions, pynames, utils from rope.refactor import patchedast -from leo.core import leoGlobals as g ### +from rope.base import leoGlobals as g ### assert g ### diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index e962e5086..98cdf5775 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -1,8 +1,7 @@ import sys import warnings - -from leo.core import leoGlobals as g +from rope.base import leoGlobals as g assert g ### diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 8ff2a191f..3bcec4d12 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -5,8 +5,8 @@ from rope.base import libutils from ropetest import testutils -from leo.core import leoGlobals as g ### - +from rope.base import leoGlobals as g ### +assert g ### class ObjectInferTest(unittest.TestCase): def setUp(self): @@ -30,18 +30,10 @@ class Sample(object): a_var = Sample() """) - trace = True # Set to False when running all tests. - - def get_ctor_name(self, file_name): - """Return .:>20""" - class_name = self.__class__.__name__ - module_name = g.shortFileName(file_name).replace('.py', '') - combined_name = f"{module_name}.{class_name}" - return f"{combined_name:>25}" + trace = False # Set to False when running all tests. if trace: g.trace_ctors = True # True: Enable tracing in ctors. - g.get_ctor_name = get_ctor_name # Inject the formatting function. def banner(s): if trace: From b6892994c162e727df38b6bf348c2ce1d5350c6d Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 29 Jan 2023 12:06:06 -0600 Subject: [PATCH 27/99] Annotate --- rope/base/leoGlobals.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rope/base/leoGlobals.py b/rope/base/leoGlobals.py index 4797be1c1..d0fd98799 100644 --- a/rope/base/leoGlobals.py +++ b/rope/base/leoGlobals.py @@ -72,8 +72,8 @@ def callers_list(n: int = 4) -> List[str]: return list(reversed(result)) -def get_ctor_name(self, file_name, width=25): - """Return .:>20""" +def get_ctor_name(self: Any, file_name: str, width: int = 25): + """Return .:>width""" class_name = self.__class__.__name__ module_name = shortFileName(file_name).replace(".py", "") combined_name = f"{module_name}.{class_name}" From 93a7bc8678525d366eb4818b80cef0941ac8cf06 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 29 Jan 2023 12:08:36 -0600 Subject: [PATCH 28/99] Add rope.base.leoGlobals --- rope/base/leoGlobals.py | 227 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 rope/base/leoGlobals.py diff --git a/rope/base/leoGlobals.py b/rope/base/leoGlobals.py new file mode 100644 index 000000000..d0fd98799 --- /dev/null +++ b/rope/base/leoGlobals.py @@ -0,0 +1,227 @@ +""" +Tracing and debugging functions from Leo. + +Duplicated here so that Rope's commit checks won't fail. +""" + +# from __future__ import annotations +import os +import sys +from typing import Any, Dict, List + + +def _callerName(n: int) -> str: + try: + # get the function name from the call stack. + f1 = sys._getframe(n) # The stack frame, n levels up. + code1 = f1.f_code # The code object + locals_ = f1.f_locals # The local namespace. + name = code1.co_name + # sfn = shortFilename(code1.co_filename) # The file name. + # line = code1.co_firstlineno + obj = locals_.get("self") + if obj and name == "__init__": + return f"{obj.__class__.__name__}.{name}" + return name + except ValueError: + # The stack is not deep enough OR + # sys._getframe does not exist on this platform. + return "" + except Exception: + return "" # "" + + +def caller(i: int = 1) -> str: + """Return the caller name i levels up the stack.""" + return callers(i + 1).split(",")[0] + + +def callers(n: int = 4) -> str: + """ + Return a string containing a comma-separated list of the calling + function's callers. + """ + # Be careful to call _callerName with smaller values of i first: + # sys._getframe throws ValueError if there are less than i entries. + i, result = 3, [] + while 1: + s = _callerName(n=i) + if s: + result.append(s) + if not s or len(result) >= n: + break + i += 1 + return ",".join(reversed(result)) + + +def callers_list(n: int = 4) -> List[str]: + """ + Return a string containing a comma-separated list of the calling + function's callers. + """ + # Be careful to call _callerName with smaller values of i first: + # sys._getframe throws ValueError if there are less than i entries. + i, result = 3, [] + while 1: + s = _callerName(n=i) + if s: + result.append(s) + if not s or len(result) >= n: + break + i += 1 + return list(reversed(result)) + + +def get_ctor_name(self: Any, file_name: str, width: int = 25): + """Return .:>width""" + class_name = self.__class__.__name__ + module_name = shortFileName(file_name).replace(".py", "") + combined_name = f"{module_name}.{class_name}" + padding = " " * max(0, 25 - len(combined_name)) + return f"{padding}{combined_name}" + + +def plural(obj: Any) -> str: + """Return "s" or "" depending on n.""" + if isinstance(obj, (list, tuple, str)): + n = len(obj) + else: + n = obj + return "" if n == 1 else "s" + + +def printObj(obj: Any, indent: str = "", tag: str = None) -> None: + """Pretty print any Python object""" + print(objToString(obj, indent=indent, tag=tag)) + + +def objToString( + obj: Any, indent: str = "", tag: str = "", concise: bool = False +) -> str: + """ + Pretty print any Python object to a string. + + concise=False: (Legacy) return a detailed string. + concise=True: Return a summary string. + """ + if tag: + print(tag.strip()) + if concise: + r = repr(obj) + if obj is None: + return f"{indent}None" + if isinstance(obj, dict): + return f"{indent}dict: {len(obj.keys())} keys" + if isinstance(obj, list): + return f"{indent}list: {len(obj)} items plural(len(obj))" + if isinstance(obj, tuple): + return f"{indent}tuple: {len(obj)} item{plural(len(obj))}" + if "method" in r: + return f"{indent}method: {obj.__name__}" + if "class" in r: + return f"{indent}class" + if "module" in r: + return f"{indent}module" + return f"{indent}object: {obj!r}" + + # concise = False + if isinstance(obj, dict): + return dictToString(obj, indent=indent) + if isinstance(obj, list): + return listToString(obj, indent=indent) + if isinstance(obj, tuple): + return tupleToString(obj, indent=indent) + if isinstance(obj, str): + # Print multi-line strings as lists. + lines = splitLines(obj) + if len(lines) > 1: + return listToString(lines, indent=indent) + return f"{indent} {obj!r}" + + +def dictToString(d: Dict[str, str], indent: str = "", tag: str = None) -> str: + """Pretty print a Python dict to a string.""" + # pylint: disable=unnecessary-lambda + if not d: + return "{}" + result = ["{\n"] + indent2 = indent + " " * 4 + n = 2 + len(indent) + max([len(repr(z)) for z in d.keys()]) + for i, key in enumerate(sorted(d, key=lambda z: repr(z))): + pad = " " * max(0, (n - len(repr(key)))) + result.append(f"{pad}{key}:") + result.append(objToString(d.get(key), indent=indent2)) + if i + 1 < len(d.keys()): + result.append(",") + result.append("\n") + result.append(indent + "}") + s = "".join(result) + return f"{tag}...\n{s}\n" if tag else s + + +def listToString(obj: Any, indent: str = "", tag: str = None) -> str: + """Pretty print a Python list to a string.""" + if not obj: + return indent + "[]" + result = [indent, "["] + indent2 = indent + " " * 4 + # I prefer not to compress lists. + for i, obj2 in enumerate(obj): + result.append("\n" + indent2) + result.append(objToString(obj2, indent=indent2)) + if i + 1 < len(obj) > 1: + result.append(",") + else: + result.append("\n" + indent) + result.append("]") + s = "".join(result) + return f"{tag}...\n{s}\n" if tag else s + + +def tupleToString(obj: Any, indent: str = "", tag: str = None) -> str: + """Pretty print a Python tuple to a string.""" + if not obj: + return "()," + result = ["("] + indent2 = indent + " " * 4 + for i, obj2 in enumerate(obj): + if len(obj) > 1: + result.append("\n" + indent2) + result.append(objToString(obj2, indent=indent2)) + if len(obj) == 1 or i + 1 < len(obj): + result.append(",") + elif len(obj) > 1: + result.append("\n" + indent) + result.append(")") + s = "".join(result) + return f"{tag}...\n{s}\n" if tag else s + + +def shortFileName(fileName: str, n: int = None) -> str: + """Return the base name of a path.""" + if n is not None: + trace('"n" keyword argument is no longer used') + return os.path.basename(fileName) if fileName else "" + + +shortFilename = shortFileName + + +def splitLines(s: str) -> List[str]: + """ + Split s into lines, preserving the number of lines and + the endings of all lines, including the last line. + """ + return s.splitlines(True) if s else [] # This is a Python string function! + + +splitlines = splitLines + + +def trace(*args: Any) -> None: + """Print the name of the calling function followed by all the args.""" + name = _callerName(2) + if name.endswith(".pyc"): + name = name[:-1] + args = "".join(str(z) for z in args) + print(f"{name} {args}") From ca2b3569a4546d9e3ce375e9b84887d5933f6b33 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 29 Jan 2023 12:17:03 -0600 Subject: [PATCH 29/99] Fix annotations for rope.base.leoGlobals --- rope/base/leoGlobals.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/rope/base/leoGlobals.py b/rope/base/leoGlobals.py index d0fd98799..4196f1580 100644 --- a/rope/base/leoGlobals.py +++ b/rope/base/leoGlobals.py @@ -7,7 +7,7 @@ # from __future__ import annotations import os import sys -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional def _callerName(n: int) -> str: @@ -96,7 +96,7 @@ def printObj(obj: Any, indent: str = "", tag: str = None) -> None: def objToString( - obj: Any, indent: str = "", tag: str = "", concise: bool = False + obj: Any, indent: str = "", tag: Optional[str] = "", concise: bool = False ) -> str: """ Pretty print any Python object to a string. @@ -139,7 +139,7 @@ def objToString( return f"{indent} {obj!r}" -def dictToString(d: Dict[str, str], indent: str = "", tag: str = None) -> str: +def dictToString(d: Dict[str, str], indent: str = "", tag: Optional[str] = None) -> str: """Pretty print a Python dict to a string.""" # pylint: disable=unnecessary-lambda if not d: @@ -159,7 +159,7 @@ def dictToString(d: Dict[str, str], indent: str = "", tag: str = None) -> str: return f"{tag}...\n{s}\n" if tag else s -def listToString(obj: Any, indent: str = "", tag: str = None) -> str: +def listToString(obj: Any, indent: str = "", tag: Optional[str] = None) -> str: """Pretty print a Python list to a string.""" if not obj: return indent + "[]" @@ -178,7 +178,7 @@ def listToString(obj: Any, indent: str = "", tag: str = None) -> str: return f"{tag}...\n{s}\n" if tag else s -def tupleToString(obj: Any, indent: str = "", tag: str = None) -> str: +def tupleToString(obj: Any, indent: str = "", tag: Optional[str] = None) -> str: """Pretty print a Python tuple to a string.""" if not obj: return "()," @@ -223,5 +223,5 @@ def trace(*args: Any) -> None: name = _callerName(2) if name.endswith(".pyc"): name = name[:-1] - args = "".join(str(z) for z in args) - print(f"{name} {args}") + args2 = "".join(str(z) for z in args) + print(f"{name} {args2}") From 5e768f2afe2cec74a2a7c2fa175dc756000082f5 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 29 Jan 2023 12:24:28 -0600 Subject: [PATCH 30/99] Fix/suppress mypy complaints --- rope/base/ast.py | 2 +- rope/base/project.py | 2 +- rope/base/pyobjects.py | 3 ++- rope/refactor/move.py | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/rope/base/ast.py b/rope/base/ast.py index 3aff82699..49362fbaf 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -5,7 +5,7 @@ from rope.base import fscommands try: - from ast import _const_node_type_names + from ast import _const_node_type_names # type:ignore except ImportError: # backported from stdlib `ast` assert sys.version_info < (3, 8) diff --git a/rope/base/project.py b/rope/base/project.py index 6d1fd8a50..3617a81ca 100644 --- a/rope/base/project.py +++ b/rope/base/project.py @@ -10,7 +10,7 @@ import rope.base.resourceobserver as resourceobserver from rope.base import exceptions, history, pycore, taskhandle, utils from rope.base.exceptions import ModuleNotFoundError -from rope.base.prefs import Prefs, get_config +from rope.base.prefs import Prefs, get_config # type:ignore from rope.base.resources import File, Folder, _ResourceMatcher try: diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 4c9fadf27..582121fe7 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -301,7 +301,8 @@ def __init__(self, pycore, ast_node, resource): @property def absolute_name(self) -> str: - return self.get_name() + ### Mypy reports a real bug. + return self.get_name() # type:ignore def _get_concluded_data(self): new_data = _ConcludedData() diff --git a/rope/refactor/move.py b/rope/refactor/move.py index 2081dee02..6bc404268 100644 --- a/rope/refactor/move.py +++ b/rope/refactor/move.py @@ -330,9 +330,9 @@ def get_changes( resources = self.project.get_python_files() if dest is None or not dest.exists(): raise exceptions.RefactoringError("Move destination does not exist.") - if dest.is_folder() and dest.has_child("__init__.py"): - dest = dest.get_child("__init__.py") - if dest.is_folder(): + if dest.is_folder() and dest.has_child("__init__.py"): # type:ignore + dest = dest.get_child("__init__.py") # type:ignore + if dest.is_folder(): # type:ignore raise exceptions.RefactoringError( "Move destination for non-modules should not be folders." ) From 5180cc595045bedf2d8c6252e349e4da37088b08 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Mon, 30 Jan 2023 09:48:57 -0600 Subject: [PATCH 31/99] Add comment re injecting g.trace_ctors --- ropetest/objectinfertest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 3bcec4d12..2bac646df 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -33,6 +33,7 @@ class Sample(object): trace = False # Set to False when running all tests. if trace: + # Make *sure* that g.trace_ctors exists only for this test. g.trace_ctors = True # True: Enable tracing in ctors. def banner(s): From 09bb07f8973d556b6b0a34b79f1ceae41f5fb599 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Mon, 30 Jan 2023 14:57:49 -0600 Subject: [PATCH 32/99] Use pprint in objToString, as in Leo, without the aliases --- rope/base/leoGlobals.py | 138 +++++++++--------------------------- ropetest/objectinfertest.py | 4 +- 2 files changed, 36 insertions(+), 106 deletions(-) diff --git a/rope/base/leoGlobals.py b/rope/base/leoGlobals.py index d0fd98799..cdca4fd16 100644 --- a/rope/base/leoGlobals.py +++ b/rope/base/leoGlobals.py @@ -6,8 +6,9 @@ # from __future__ import annotations import os +import pprint import sys -from typing import Any, Dict, List +from typing import Any, List def _callerName(n: int) -> str: @@ -81,6 +82,35 @@ def get_ctor_name(self: Any, file_name: str, width: int = 25): return f"{padding}{combined_name}" +def objToString(obj: Any, indent: int = 0, width: int = 120) -> str: + """ + Pretty print any Python object to a string. + """ + + s = pprint.pformat( + obj, + compact=False, + depth=None, + # indent=len(indent) if isinstance(indent, str) else indent, + indent=indent, + sort_dicts=True, + # underscore_numbers=False, + width=width, + ) + if s and isinstance(obj, str) and "\n" in s: + # Weird: strip () + if s[0] == "(": + s = s[1:] + if s and s[-1] == ")": + s = s[:-1] + results = ["[\n"] + for i, z in enumerate(splitLines(s)): + results.append(f" {i:4}: {z!s}") + results.append("\n]\n") + return "".join(results) + return s + + def plural(obj: Any) -> str: """Return "s" or "" depending on n.""" if isinstance(obj, (list, tuple, str)): @@ -90,111 +120,11 @@ def plural(obj: Any) -> str: return "" if n == 1 else "s" -def printObj(obj: Any, indent: str = "", tag: str = None) -> None: - """Pretty print any Python object""" - print(objToString(obj, indent=indent, tag=tag)) - - -def objToString( - obj: Any, indent: str = "", tag: str = "", concise: bool = False -) -> str: - """ - Pretty print any Python object to a string. - - concise=False: (Legacy) return a detailed string. - concise=True: Return a summary string. - """ +def printObj(obj: Any, tag: str = None, indent: int = 0) -> None: + """Pretty print any Python object using g.pr.""" if tag: print(tag.strip()) - if concise: - r = repr(obj) - if obj is None: - return f"{indent}None" - if isinstance(obj, dict): - return f"{indent}dict: {len(obj.keys())} keys" - if isinstance(obj, list): - return f"{indent}list: {len(obj)} items plural(len(obj))" - if isinstance(obj, tuple): - return f"{indent}tuple: {len(obj)} item{plural(len(obj))}" - if "method" in r: - return f"{indent}method: {obj.__name__}" - if "class" in r: - return f"{indent}class" - if "module" in r: - return f"{indent}module" - return f"{indent}object: {obj!r}" - - # concise = False - if isinstance(obj, dict): - return dictToString(obj, indent=indent) - if isinstance(obj, list): - return listToString(obj, indent=indent) - if isinstance(obj, tuple): - return tupleToString(obj, indent=indent) - if isinstance(obj, str): - # Print multi-line strings as lists. - lines = splitLines(obj) - if len(lines) > 1: - return listToString(lines, indent=indent) - return f"{indent} {obj!r}" - - -def dictToString(d: Dict[str, str], indent: str = "", tag: str = None) -> str: - """Pretty print a Python dict to a string.""" - # pylint: disable=unnecessary-lambda - if not d: - return "{}" - result = ["{\n"] - indent2 = indent + " " * 4 - n = 2 + len(indent) + max([len(repr(z)) for z in d.keys()]) - for i, key in enumerate(sorted(d, key=lambda z: repr(z))): - pad = " " * max(0, (n - len(repr(key)))) - result.append(f"{pad}{key}:") - result.append(objToString(d.get(key), indent=indent2)) - if i + 1 < len(d.keys()): - result.append(",") - result.append("\n") - result.append(indent + "}") - s = "".join(result) - return f"{tag}...\n{s}\n" if tag else s - - -def listToString(obj: Any, indent: str = "", tag: str = None) -> str: - """Pretty print a Python list to a string.""" - if not obj: - return indent + "[]" - result = [indent, "["] - indent2 = indent + " " * 4 - # I prefer not to compress lists. - for i, obj2 in enumerate(obj): - result.append("\n" + indent2) - result.append(objToString(obj2, indent=indent2)) - if i + 1 < len(obj) > 1: - result.append(",") - else: - result.append("\n" + indent) - result.append("]") - s = "".join(result) - return f"{tag}...\n{s}\n" if tag else s - - -def tupleToString(obj: Any, indent: str = "", tag: str = None) -> str: - """Pretty print a Python tuple to a string.""" - if not obj: - return "()," - result = ["("] - indent2 = indent + " " * 4 - for i, obj2 in enumerate(obj): - if len(obj) > 1: - result.append("\n" + indent2) - result.append(objToString(obj2, indent=indent2)) - if len(obj) == 1 or i + 1 < len(obj): - result.append(",") - elif len(obj) > 1: - result.append("\n" + indent) - result.append(")") - s = "".join(result) - return f"{tag}...\n{s}\n" if tag else s + print(objToString(obj, indent=indent)) def shortFileName(fileName: str, n: int = None) -> str: diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 2bac646df..f03236341 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -30,7 +30,7 @@ class Sample(object): a_var = Sample() """) - trace = False # Set to False when running all tests. + trace = True # Set to False when running all tests. if trace: # Make *sure* that g.trace_ctors exists only for this test. @@ -68,7 +68,7 @@ def banner(s): # scope is a GlobalScope. It might be any subclass of Scope. # scope.pyobject is a pyobjectsdef.PyModule. - if trace: g.trace('*** scope.pyobject', scope.pyobject) + ### if trace: g.trace('*** scope.pyobject', scope.pyobject) # *** Calling scope["Sample"] (via _ScopeVisitor._ClassDef) # instantiates pyobjects.PyClass *and* pyobjectsdef.PyClass. From 198c6701d8cec9e266f36e4cd99b400bede3518d Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Mon, 30 Jan 2023 15:24:09 -0600 Subject: [PATCH 33/99] Use rope.base.utils.debugutils instead of rope.base.leoGlobals --- rope/base/pynames.py | 2 +- rope/base/pyobjects.py | 2 +- rope/base/pyobjectsdef.py | 2 +- rope/base/pyscopes.py | 2 +- rope/base/utils/__init__.py | 2 +- rope/base/{leoGlobals.py => utils/debugutils.py} | 0 ropetest/objectinfertest.py | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename rope/base/{leoGlobals.py => utils/debugutils.py} (100%) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index f33e9166e..6986c6696 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -10,7 +10,7 @@ from rope.base import pyobjectsdef -from rope.base import leoGlobals as g ### +from rope.base.utils import debugutils as g ### assert g ### diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 239276684..adae4fcea 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -2,7 +2,7 @@ from rope.base import ast, exceptions, utils -from rope.base import leoGlobals as g ### +from rope.base.utils import debugutils as g ### assert g ### diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 08841adb7..f7afe19ef 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -15,7 +15,7 @@ utils, ) -from rope.base import leoGlobals as g ### +from rope.base.utils import debugutils as g ### assert g ### diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index b97b8bf51..b5ff1c76b 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -2,7 +2,7 @@ from rope.base import ast, codeanalyze, exceptions, pynames, utils from rope.refactor import patchedast -from rope.base import leoGlobals as g ### +from rope.base.utils import debugutils as g ### assert g ### diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 98cdf5775..9e4f4bd9b 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -1,7 +1,7 @@ import sys import warnings -from rope.base import leoGlobals as g +from rope.base.utils import debugutils as g assert g ### diff --git a/rope/base/leoGlobals.py b/rope/base/utils/debugutils.py similarity index 100% rename from rope/base/leoGlobals.py rename to rope/base/utils/debugutils.py diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index f03236341..af766ab4f 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -5,7 +5,7 @@ from rope.base import libutils from ropetest import testutils -from rope.base import leoGlobals as g ### +from rope.base.utils import debugutils as g ### assert g ### class ObjectInferTest(unittest.TestCase): From 00cdfff269d8c7ec84bd18e2c0868315d672a418 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Mon, 30 Jan 2023 15:29:28 -0600 Subject: [PATCH 34/99] Remove unused kwarg --- rope/base/utils/debugutils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rope/base/utils/debugutils.py b/rope/base/utils/debugutils.py index cdca4fd16..0dc959493 100644 --- a/rope/base/utils/debugutils.py +++ b/rope/base/utils/debugutils.py @@ -127,10 +127,8 @@ def printObj(obj: Any, tag: str = None, indent: int = 0) -> None: print(objToString(obj, indent=indent)) -def shortFileName(fileName: str, n: int = None) -> str: +def shortFileName(fileName: str) -> str: """Return the base name of a path.""" - if n is not None: - trace('"n" keyword argument is no longer used') return os.path.basename(fileName) if fileName else "" From b254d69fdb29370ac80b227609a175c4d3a4467c Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Tue, 31 Jan 2023 09:49:58 -0600 Subject: [PATCH 35/99] Improve and simplify tracing of ctors --- rope/base/pyobjects.py | 4 +-- rope/base/pyobjectsdef.py | 4 +-- rope/base/utils/debugutils.py | 2 ++ ropetest/objectinfertest.py | 49 +++++++++++++++++------------------ 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index adae4fcea..fb2bbe0de 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -175,7 +175,7 @@ def __init__(self, pycore, ast_node, parent): self.concluded_attributes = self.get_module()._get_concluded_data() self.attributes = self.get_module()._get_concluded_data() self.defineds = None - if getattr(g, "trace_ctors", None): ### + if g.trace_ctors: ### g.trace( f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", g.callers(), @@ -313,7 +313,7 @@ def __init__(self, pycore, ast_node, resource): self.concluded_data = [] AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) - if getattr(g, "trace_ctors", None): ### + if g.trace_ctors: ### g.trace( f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", g.callers(), diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index f7afe19ef..c57c004c5 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -137,7 +137,7 @@ def __init__(self, pycore, ast_node, parent): rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent) self.parent = parent self._superclasses = self.get_module()._get_concluded_data() - if getattr(g, "trace_ctors", None): ### + if g.trace_ctors: ### g.trace(f"{g.get_ctor_name(self, __file__)} {' ':14}", g.callers()) def get_superclasses(self): @@ -188,7 +188,7 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.star_imports = [] self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) - if getattr(g, "trace_ctors", None): ### + if g.trace_ctors: ### g.trace(f"{g.get_ctor_name(self, __file__)} {' ':14}", g.callers()) super().__init__(pycore, node, resource) diff --git a/rope/base/utils/debugutils.py b/rope/base/utils/debugutils.py index 0dc959493..27d5251f9 100644 --- a/rope/base/utils/debugutils.py +++ b/rope/base/utils/debugutils.py @@ -10,6 +10,8 @@ import sys from typing import Any, List +trace_ctors = False # For traces in various ctors. + def _callerName(n: int) -> str: try: diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index af766ab4f..73893213d 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -14,10 +14,9 @@ def setUp(self): Init self.project to a new Project instance for this test, with default prefs. self.project.fscommands manages temp files in a temp directory. """ - if 1: - print('') # For single tests. Does not affect the test-r or full-test-r scripts. super().setUp() self.project = testutils.sample_project() + g.trace_ctors = False ### def tearDown(self): testutils.remove_project(self.project) @@ -29,63 +28,64 @@ class Sample(object): pass a_var = Sample() """) - + trace = True # Set to False when running all tests. - if trace: - # Make *sure* that g.trace_ctors exists only for this test. - g.trace_ctors = True # True: Enable tracing in ctors. - def banner(s): if trace: - print(f"\n===== {s}\n") - + print(f"\n{g._callerName(2)}: ===== {s}\n") + + if trace: + print('') + g.trace_ctors = True # True: Enable tracing in ctors. + + banner('after setUp') - + # 1. setUp creates self.project. # setUp instantiates self.project to a Project instance. # self.project = testutils.sample_project() - + # 2. get_string_scope sets self.scope to the scope of the test string. - + # Sets self.scope to pyobjectsdef.PyModule(project.pycore, code, ...) # (code is the test string, defined above.) - + # ??? Instantiating the pyobjectsdef.PyModule does all the work ??? - + # PyDefinedObject.__init__ calls: - + # self.concluded_attributes = self.get_module()._get_concluded_data() # self.attributes = self.get_module()._get_concluded_data() - + # But all attributes are empty for this test. scope = libutils.get_string_scope(self.project, code) - + banner('after get_string_scope') - + # scope is a GlobalScope. It might be any subclass of Scope. # scope.pyobject is a pyobjectsdef.PyModule. - + ### if trace: g.trace('*** scope.pyobject', scope.pyobject) # *** Calling scope["Sample"] (via _ScopeVisitor._ClassDef) # instantiates pyobjects.PyClass *and* pyobjectsdef.PyClass. # (Because pyobjectsDef.PyClass is a subclass of pyobjects.PyClass.) # scope["Sample"] is a pynamesdef.DefinedName. - + sample_class = scope["Sample"].get_object() - + banner('after sample_class = scope["Sample"].get_object()') - - + + # sample_class is a pyobjectsdef.PyClass ("::Sample" at ...) # scope["Sample"] is a DefinedName. # scope["Sample"].pyobject is a pyobjectsdef.PyClass. a_var = scope["a_var"].get_object() - + # a_var is a pyobjects.PyObject # a_var.get_type() is a pyobjectsdef.PyClass ("::Sample" at ...) @@ -96,7 +96,6 @@ def banner(s): if trace: print(f"sample_class: {sample_class}") self.assertEqual(sample_class, a_var.get_type()) - def test_simple_type_inferencing_classes_defined_in_holding_scope(self): code = dedent("""\ class Sample(object): From e1daee0c9a4a36b2218146ad3c4d3a071c181d1b Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Tue, 31 Jan 2023 09:53:54 -0600 Subject: [PATCH 36/99] Removed unused import --- rope/base/utils/debugutils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rope/base/utils/debugutils.py b/rope/base/utils/debugutils.py index 27d5251f9..559daf873 100644 --- a/rope/base/utils/debugutils.py +++ b/rope/base/utils/debugutils.py @@ -4,7 +4,6 @@ Duplicated here so that Rope's commit checks won't fail. """ -# from __future__ import annotations import os import pprint import sys From 70f9f4caaa0a021920840151cd2363b19597ca07 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Tue, 31 Jan 2023 10:10:39 -0600 Subject: [PATCH 37/99] Tweak g.objToString --- rope/base/utils/debugutils.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/rope/base/utils/debugutils.py b/rope/base/utils/debugutils.py index 559daf873..98c909161 100644 --- a/rope/base/utils/debugutils.py +++ b/rope/base/utils/debugutils.py @@ -88,16 +88,9 @@ def objToString(obj: Any, indent: int = 0, width: int = 120) -> str: Pretty print any Python object to a string. """ - s = pprint.pformat( - obj, - compact=False, - depth=None, - # indent=len(indent) if isinstance(indent, str) else indent, - indent=indent, - sort_dicts=True, - # underscore_numbers=False, - width=width, - ) + s = pprint.pformat(obj, indent=indent, width=width) + + # Print line numbers for multi-line strings. if s and isinstance(obj, str) and "\n" in s: # Weird: strip () if s[0] == "(": From f466b0e11164c7bf1de049ce534dc01e1de14bc6 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Tue, 31 Jan 2023 10:37:54 -0600 Subject: [PATCH 38/99] More tweaks to objToString --- rope/base/utils/debugutils.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/rope/base/utils/debugutils.py b/rope/base/utils/debugutils.py index 98c909161..246257e46 100644 --- a/rope/base/utils/debugutils.py +++ b/rope/base/utils/debugutils.py @@ -89,15 +89,12 @@ def objToString(obj: Any, indent: int = 0, width: int = 120) -> str: """ s = pprint.pformat(obj, indent=indent, width=width) - - # Print line numbers for multi-line strings. if s and isinstance(obj, str) and "\n" in s: - # Weird: strip () - if s[0] == "(": - s = s[1:] - if s and s[-1] == ")": - s = s[:-1] + # When len(s) > width, parens enclose the representation! + if len(s) >= width and s.startswith("(") and s.endswith(")"): + s = s[1:-1] results = ["[\n"] + # Include line numbers. for i, z in enumerate(splitLines(s)): results.append(f" {i:4}: {z!s}") results.append("\n]\n") From 1b4bcc54c5b2e12dd1fa2e4f5a0217148c9300e3 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Tue, 31 Jan 2023 12:11:13 -0600 Subject: [PATCH 39/99] Improve objToString --- rope/base/utils/debugutils.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/rope/base/utils/debugutils.py b/rope/base/utils/debugutils.py index 246257e46..6ba952eaa 100644 --- a/rope/base/utils/debugutils.py +++ b/rope/base/utils/debugutils.py @@ -87,19 +87,14 @@ def objToString(obj: Any, indent: int = 0, width: int = 120) -> str: """ Pretty print any Python object to a string. """ - - s = pprint.pformat(obj, indent=indent, width=width) - if s and isinstance(obj, str) and "\n" in s: - # When len(s) > width, parens enclose the representation! - if len(s) >= width and s.startswith("(") and s.endswith(")"): - s = s[1:-1] - results = ["[\n"] - # Include line numbers. - for i, z in enumerate(splitLines(s)): - results.append(f" {i:4}: {z!s}") - results.append("\n]\n") - return "".join(results) - return s + if not isinstance(obj, str): + s = pprint.pformat(obj, indent=indent, width=width) + return f"{obj.__class__.__name__}: {pprint.saferepr(s)}" + if "\n" not in obj: + return f"str: {obj!r}" + # Return the enumerated lines of the string. + lines = "".join([f" {i:4}: {z!r}\n" for i, z in enumerate(splitLines(obj))]) + return f"str: [\n{lines}]\n" def plural(obj: Any) -> str: From d4dccd7e9717f239921758221fc64b72b0a1f98c Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Tue, 31 Jan 2023 12:34:06 -0600 Subject: [PATCH 40/99] Revise, following Leo revisions --- rope/base/utils/debugutils.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/rope/base/utils/debugutils.py b/rope/base/utils/debugutils.py index 6ba952eaa..fb45605fd 100644 --- a/rope/base/utils/debugutils.py +++ b/rope/base/utils/debugutils.py @@ -83,18 +83,19 @@ def get_ctor_name(self: Any, file_name: str, width: int = 25): return f"{padding}{combined_name}" -def objToString(obj: Any, indent: int = 0, width: int = 120) -> str: +def objToString(obj: Any, indent: int = 0, tag: str = None, width: int = 120) -> str: """ Pretty print any Python object to a string. """ if not isinstance(obj, str): - s = pprint.pformat(obj, indent=indent, width=width) - return f"{obj.__class__.__name__}: {pprint.saferepr(s)}" - if "\n" not in obj: - return f"str: {obj!r}" - # Return the enumerated lines of the string. - lines = "".join([f" {i:4}: {z!r}\n" for i, z in enumerate(splitLines(obj))]) - return f"str: [\n{lines}]\n" + result = pprint.pformat(obj, indent=indent, width=width) + elif "\n" not in obj: + result = repr(obj) + else: + # Return the enumerated lines of the string. + lines = "".join([f" {i:4}: {z!r}\n" for i, z in enumerate(splitLines(obj))]) + result = f"[\n{lines}]\n" + return f"{tag.strip()}: {result}" if tag.strip() else result def plural(obj: Any) -> str: @@ -108,9 +109,7 @@ def plural(obj: Any) -> str: def printObj(obj: Any, tag: str = None, indent: int = 0) -> None: """Pretty print any Python object using g.pr.""" - if tag: - print(tag.strip()) - print(objToString(obj, indent=indent)) + print(objToString(obj, indent=indent, tag=tag)) def shortFileName(fileName: str) -> str: From 945d81741a26aa22d8cbfc043f9fba34077485c4 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 1 Feb 2023 00:24:03 -0600 Subject: [PATCH 41/99] Tweaks, per Leo PR --- rope/base/utils/debugutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rope/base/utils/debugutils.py b/rope/base/utils/debugutils.py index fb45605fd..82af67d10 100644 --- a/rope/base/utils/debugutils.py +++ b/rope/base/utils/debugutils.py @@ -95,7 +95,7 @@ def objToString(obj: Any, indent: int = 0, tag: str = None, width: int = 120) -> # Return the enumerated lines of the string. lines = "".join([f" {i:4}: {z!r}\n" for i, z in enumerate(splitLines(obj))]) result = f"[\n{lines}]\n" - return f"{tag.strip()}: {result}" if tag.strip() else result + return f"{tag.strip()}: {result}" if tag and tag.strip() else result def plural(obj: Any) -> str: From aa203270bf86d5ec1356a0536ee0b1ad10940923 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 1 Feb 2023 00:27:06 -0600 Subject: [PATCH 42/99] Fix docstring. It's not the same as in Leo --- rope/base/utils/debugutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rope/base/utils/debugutils.py b/rope/base/utils/debugutils.py index 82af67d10..385109a66 100644 --- a/rope/base/utils/debugutils.py +++ b/rope/base/utils/debugutils.py @@ -108,7 +108,7 @@ def plural(obj: Any) -> str: def printObj(obj: Any, tag: str = None, indent: int = 0) -> None: - """Pretty print any Python object using g.pr.""" + """Pretty print any Python object.""" print(objToString(obj, indent=indent, tag=tag)) From bebdb50635b6f491d1997c9bd894df8e096e9c53 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 1 Feb 2023 00:43:21 -0600 Subject: [PATCH 43/99] Blacken all files after upgrading black. --- rope/base/oi/doa.py | 2 +- rope/base/oi/runmod.py | 2 +- rope/base/oi/type_hinting/evaluate.py | 5 ----- rope/base/oi/type_hinting/providers/docstrings.py | 3 --- rope/base/oi/type_hinting/resolvers/types.py | 2 +- rope/base/oi/type_hinting/utils.py | 2 -- rope/base/pycore.py | 1 - rope/base/pyobjects.py | 2 -- rope/base/stdmods.py | 1 - rope/contrib/generate.py | 1 - rope/refactor/extract.py | 1 - rope/refactor/importutils/importinfo.py | 1 - rope/refactor/inline.py | 2 -- 13 files changed, 3 insertions(+), 22 deletions(-) diff --git a/rope/base/oi/doa.py b/rope/base/oi/doa.py index 83fc500cb..57b68ce5c 100644 --- a/rope/base/oi/doa.py +++ b/rope/base/oi/doa.py @@ -28,7 +28,7 @@ def _compat_compare_digest(a, b): # Computes the bitwise difference of all characters in the two strings # before returning whether or not they are equal. difference = 0 - for (a_char, b_char) in zip(a, b): + for a_char, b_char in zip(a, b): difference |= ord(a_char) ^ ord(b_char) return difference == 0 diff --git a/rope/base/oi/runmod.py b/rope/base/oi/runmod.py index 1ed9ac30c..4679ebb45 100644 --- a/rope/base/oi/runmod.py +++ b/rope/base/oi/runmod.py @@ -101,7 +101,7 @@ def on_function_call(self, frame, event, arg): returned, ) self.sender.send_data(data) - except (TypeError): + except TypeError: pass return self.on_function_call diff --git a/rope/base/oi/type_hinting/evaluate.py b/rope/base/oi/type_hinting/evaluate.py index ff8af387d..e3fa9f4c5 100644 --- a/rope/base/oi/type_hinting/evaluate.py +++ b/rope/base/oi/type_hinting/evaluate.py @@ -8,7 +8,6 @@ class SymbolBase: - name = None # node/token type name def __init__(self): @@ -128,7 +127,6 @@ def led(self, left, parser): class Lexer: - _token_pattern = re.compile( r""" \s* @@ -180,7 +178,6 @@ def _tokenize_expr(self, program): class Parser: - token = None next = None @@ -322,7 +319,6 @@ def evaluate(self, pyobject): class Compiler: - parser_factory = Parser lexer_factory = Lexer symbol_table = symbol_table @@ -343,7 +339,6 @@ def __call__(self, program): class Evaluator: - compile = compile def __call__(self, program, pyobject): diff --git a/rope/base/oi/type_hinting/providers/docstrings.py b/rope/base/oi/type_hinting/providers/docstrings.py index c8497c3e9..d50d2fd67 100644 --- a/rope/base/oi/type_hinting/providers/docstrings.py +++ b/rope/base/oi/type_hinting/providers/docstrings.py @@ -106,7 +106,6 @@ def __call__(self, docstring): class DocstringParamParser(IParamParser): - DOCSTRING_PARAM_PATTERNS = [ r"\s*:type\s+%s:\s*([^\n]+)", # Sphinx r"\s*:param\s+(\w+)\s+%s:[^\n]+", # Sphinx param with type @@ -144,7 +143,6 @@ def __call__(self, docstring, param_name): class DocstringReturnParser(IReturnParser): - DOCSTRING_RETURN_PATTERNS = [ re.compile(r"\s*:rtype:\s*([^\n]+)", re.M), # Sphinx re.compile(r"\s*@rtype:\s*([^\n]+)", re.M), # Epydoc @@ -164,7 +162,6 @@ def __call__(self, docstring): class RSTRoleStrip: - RST_ROLE_PATTERN = re.compile(r":[^`]+:`([^`]+)`") def __call__(self, type_str): diff --git a/rope/base/oi/type_hinting/resolvers/types.py b/rope/base/oi/type_hinting/resolvers/types.py index 252696a65..5a50ae1ce 100644 --- a/rope/base/oi/type_hinting/resolvers/types.py +++ b/rope/base/oi/type_hinting/resolvers/types.py @@ -12,5 +12,5 @@ def __call__(self, hint, pyobject): """ try: return evaluate.evaluate(hint, pyobject) - except (Exception): + except Exception: pass diff --git a/rope/base/oi/type_hinting/utils.py b/rope/base/oi/type_hinting/utils.py index caffd61ed..988e6697a 100644 --- a/rope/base/oi/type_hinting/utils.py +++ b/rope/base/oi/type_hinting/utils.py @@ -8,7 +8,6 @@ def get_super_func(pyfunc): - if not isinstance(pyfunc.parent, PyClass): return @@ -114,7 +113,6 @@ def resolve_type( class ParametrizeType: - _supported_mapping = { "builtins.list": "rope.base.builtins.get_list", "builtins.tuple": "rope.base.builtins.get_tuple", diff --git a/rope/base/pycore.py b/rope/base/pycore.py index 2f1e92212..c1ad7e426 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -215,7 +215,6 @@ def analyze_module( ) def get_classes(self, task_handle=taskhandle.DEFAULT_TASK_HANDLE): - warnings.warn( "`PyCore.get_classes()` is deprecated", DeprecationWarning, stacklevel=2 ) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index fb2bbe0de..9cf00875e 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -303,7 +303,6 @@ def __str__(self): ### def _ekr_dump(self): - g.printObj(self.data, tag=f"***** pyobjects._ConcludedData: {id(self)}") @@ -336,7 +335,6 @@ def get_resource(self): return self.resource def _ekr_dump_concluded_data(self): - g.trace("(pyobjects._PyModule._ekr_dump_concluded_data)") tag = self.get_name() try: diff --git a/rope/base/stdmods.py b/rope/base/stdmods.py index 4d944cb30..8245e626a 100644 --- a/rope/base/stdmods.py +++ b/rope/base/stdmods.py @@ -6,7 +6,6 @@ def _stdlib_path(): - return os.path.dirname(inspect.getsourcefile(inspect)) diff --git a/rope/contrib/generate.py b/rope/contrib/generate.py index 57c7686c6..2e6c81b49 100644 --- a/rope/contrib/generate.py +++ b/rope/contrib/generate.py @@ -36,7 +36,6 @@ def create_generate( offset: int, goal_resource: Optional[Resource] = None, ): - """A factory for creating `Generate` objects Used in https://github.com/python-rope/ropemode but not in Rope itself. diff --git a/rope/refactor/extract.py b/rope/refactor/extract.py index f6e0953ac..8df49218b 100644 --- a/rope/refactor/extract.py +++ b/rope/refactor/extract.py @@ -35,7 +35,6 @@ # There are a few more helper functions and classes used by above # classes. class _ExtractRefactoring: - kind_prefixes: Dict[str, str] = {} def __init__(self, project, resource, start_offset, end_offset, variable=False): diff --git a/rope/refactor/importutils/importinfo.py b/rope/refactor/importutils/importinfo.py index 18b6646b2..ec9be5fb9 100644 --- a/rope/refactor/importutils/importinfo.py +++ b/rope/refactor/importutils/importinfo.py @@ -190,7 +190,6 @@ def is_star_import(self): class EmptyImport(ImportInfo): - names_and_aliases: List[str] = [] def is_empty(self): diff --git a/rope/refactor/inline.py b/rope/refactor/inline.py index 7be047f6c..23c8a8291 100644 --- a/rope/refactor/inline.py +++ b/rope/refactor/inline.py @@ -439,7 +439,6 @@ def _calculate_header(self, primary, pyname, call): return header, to_be_inlined def _calculate_definition(self, primary, pyname, call, host_vars, returns): - header, to_be_inlined = self._calculate_header(primary, pyname, call) source = header + self.body @@ -454,7 +453,6 @@ def _calculate_definition(self, primary, pyname, call, host_vars, returns): # If there is a name conflict, all variable names # inside the inlined function are renamed if set(all_names).intersection(set(host_vars)): - prefix = next(_DefinitionGenerator.unique_prefix) guest = libutils.get_string_module(self.project, source, self.resource) From 1a4fca705260721ae10127dad034ec3939865962 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 1 Feb 2023 12:03:23 -0600 Subject: [PATCH 44/99] Rename debugutils.py to debug_utils.py --- rope/base/pynames.py | 2 +- rope/base/pyobjects.py | 2 +- rope/base/pyobjectsdef.py | 2 +- rope/base/pyscopes.py | 2 +- rope/base/utils/__init__.py | 2 +- rope/base/utils/{debugutils.py => debug_utils.py} | 0 ropetest/objectinfertest.py | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename rope/base/utils/{debugutils.py => debug_utils.py} (100%) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 6986c6696..91eb10b23 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -10,7 +10,7 @@ from rope.base import pyobjectsdef -from rope.base.utils import debugutils as g ### +from rope.base.utils import debug_utils as g ### assert g ### diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 9cf00875e..0cf26130c 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -2,7 +2,7 @@ from rope.base import ast, exceptions, utils -from rope.base.utils import debugutils as g ### +from rope.base.utils import debug_utils as g ### assert g ### diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index c57c004c5..08d486eec 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -15,7 +15,7 @@ utils, ) -from rope.base.utils import debugutils as g ### +from rope.base.utils import debug_utils as g ### assert g ### diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index b5ff1c76b..f69519007 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -2,7 +2,7 @@ from rope.base import ast, codeanalyze, exceptions, pynames, utils from rope.refactor import patchedast -from rope.base.utils import debugutils as g ### +from rope.base.utils import debug_utils as g ### assert g ### diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 9e4f4bd9b..8bf1bd002 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -1,7 +1,7 @@ import sys import warnings -from rope.base.utils import debugutils as g +from rope.base.utils import debug_utils as g assert g ### diff --git a/rope/base/utils/debugutils.py b/rope/base/utils/debug_utils.py similarity index 100% rename from rope/base/utils/debugutils.py rename to rope/base/utils/debug_utils.py diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 73893213d..539f1a477 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -5,7 +5,7 @@ from rope.base import libutils from ropetest import testutils -from rope.base.utils import debugutils as g ### +from rope.base.utils import debug_utils as g ### assert g ### class ObjectInferTest(unittest.TestCase): From fd69bfafe0ec377090b02763efed19b2fcd1e3a3 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 1 Feb 2023 12:06:46 -0600 Subject: [PATCH 45/99] Add trace lists --- rope/base/utils/debug_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rope/base/utils/debug_utils.py b/rope/base/utils/debug_utils.py index 385109a66..dd35473af 100644 --- a/rope/base/utils/debug_utils.py +++ b/rope/base/utils/debug_utils.py @@ -10,6 +10,8 @@ from typing import Any, List trace_ctors = False # For traces in various ctors. +visitor_trace_list: List[str] = None # List of visitors to trace. +ctor_trace_list: List[str] = None # List of ctors to trace. def _callerName(n: int) -> str: From 264f972e2bf78bfe31f694abfe7b0415c251d778 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 1 Feb 2023 12:17:30 -0600 Subject: [PATCH 46/99] Use pep8 names in debug_utils --- rope/base/pyobjects.py | 6 ++-- rope/base/utils/__init__.py | 2 +- rope/base/utils/debug_utils.py | 60 +++++++++++++++------------------- ropetest/objectinfertest.py | 2 +- 4 files changed, 31 insertions(+), 39 deletions(-) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 0cf26130c..956bc88ec 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -303,7 +303,7 @@ def __str__(self): ### def _ekr_dump(self): - g.printObj(self.data, tag=f"***** pyobjects._ConcludedData: {id(self)}") + g.print_obj(self.data, tag=f"***** pyobjects._ConcludedData: {id(self)}") class _PyModule(PyDefinedObject, AbstractModule): @@ -339,11 +339,11 @@ def _ekr_dump_concluded_data(self): tag = self.get_name() try: for i, z in enumerate(self.concluded_data): - g.printObj(f"{i:3} {z!s}", tag=tag) + g.print_obj(f"{i:3} {z!s}", tag=tag) # z._ekr_dump() except TypeError: z = self.concluded_data - g.printObj(f"{z!s}", tag=tag) + g.print_obj(f"{z!s}", tag=tag) # z._ekr_dump() diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 8bf1bd002..a764b5715 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -47,7 +47,7 @@ def _wrapper(self, *args, **kwargs): print(f"{tag} ivar: {injected_name:>30} = {description}") else: print("") - g.printObj( + g.print_obj( obj, tag=f"{tag} ivar: {injected_name} = {description}" ) setattr(self, ivar_name, obj) diff --git a/rope/base/utils/debug_utils.py b/rope/base/utils/debug_utils.py index dd35473af..a0fd9b844 100644 --- a/rope/base/utils/debug_utils.py +++ b/rope/base/utils/debug_utils.py @@ -14,15 +14,13 @@ ctor_trace_list: List[str] = None # List of ctors to trace. -def _callerName(n: int) -> str: +def _caller_name(n: int) -> str: try: - # get the function name from the call stack. + # Get the function name from the call stack. f1 = sys._getframe(n) # The stack frame, n levels up. code1 = f1.f_code # The code object locals_ = f1.f_locals # The local namespace. name = code1.co_name - # sfn = shortFilename(code1.co_filename) # The file name. - # line = code1.co_firstlineno obj = locals_.get("self") if obj and name == "__init__": return f"{obj.__class__.__name__}.{name}" @@ -45,11 +43,11 @@ def callers(n: int = 4) -> str: Return a string containing a comma-separated list of the calling function's callers. """ - # Be careful to call _callerName with smaller values of i first: + # Be careful to call _caller_name with smaller values of i first: # sys._getframe throws ValueError if there are less than i entries. i, result = 3, [] while 1: - s = _callerName(n=i) + s = _caller_name(n=i) if s: result.append(s) if not s or len(result) >= n: @@ -63,11 +61,11 @@ def callers_list(n: int = 4) -> List[str]: Return a string containing a comma-separated list of the calling function's callers. """ - # Be careful to call _callerName with smaller values of i first: + # Be careful to call _caller_name with smaller values of i first: # sys._getframe throws ValueError if there are less than i entries. i, result = 3, [] while 1: - s = _callerName(n=i) + s = _caller_name(n=i) if s: result.append(s) if not s or len(result) >= n: @@ -79,27 +77,12 @@ def callers_list(n: int = 4) -> List[str]: def get_ctor_name(self: Any, file_name: str, width: int = 25): """Return .:>width""" class_name = self.__class__.__name__ - module_name = shortFileName(file_name).replace(".py", "") + module_name = short_file_name(file_name).replace(".py", "") combined_name = f"{module_name}.{class_name}" padding = " " * max(0, 25 - len(combined_name)) return f"{padding}{combined_name}" -def objToString(obj: Any, indent: int = 0, tag: str = None, width: int = 120) -> str: - """ - Pretty print any Python object to a string. - """ - if not isinstance(obj, str): - result = pprint.pformat(obj, indent=indent, width=width) - elif "\n" not in obj: - result = repr(obj) - else: - # Return the enumerated lines of the string. - lines = "".join([f" {i:4}: {z!r}\n" for i, z in enumerate(splitLines(obj))]) - result = f"[\n{lines}]\n" - return f"{tag.strip()}: {result}" if tag and tag.strip() else result - - def plural(obj: Any) -> str: """Return "s" or "" depending on n.""" if isinstance(obj, (list, tuple, str)): @@ -109,20 +92,17 @@ def plural(obj: Any) -> str: return "" if n == 1 else "s" -def printObj(obj: Any, tag: str = None, indent: int = 0) -> None: +def print_obj(obj: Any, tag: str = None, indent: int = 0) -> None: """Pretty print any Python object.""" - print(objToString(obj, indent=indent, tag=tag)) + print(to_string(obj, indent=indent, tag=tag)) -def shortFileName(fileName: str) -> str: +def short_file_name(file_name: str) -> str: """Return the base name of a path.""" - return os.path.basename(fileName) if fileName else "" + return os.path.basename(file_name) if file_name else "" -shortFilename = shortFileName - - -def splitLines(s: str) -> List[str]: +def split_lines(s: str) -> List[str]: """ Split s into lines, preserving the number of lines and the endings of all lines, including the last line. @@ -130,12 +110,24 @@ def splitLines(s: str) -> List[str]: return s.splitlines(True) if s else [] # This is a Python string function! -splitlines = splitLines +def to_string(obj: Any, indent: int = 0, tag: str = None, width: int = 120) -> str: + """ + Pretty print any Python object to a string. + """ + if not isinstance(obj, str): + result = pprint.pformat(obj, indent=indent, width=width) + elif "\n" not in obj: + result = repr(obj) + else: + # Return the enumerated lines of the string. + lines = "".join([f" {i:4}: {z!r}\n" for i, z in enumerate(split_lines(obj))]) + result = f"[\n{lines}]\n" + return f"{tag.strip()}: {result}" if tag and tag.strip() else result def trace(*args: Any) -> None: """Print the name of the calling function followed by all the args.""" - name = _callerName(2) + name = _caller_name(2) if name.endswith(".pyc"): name = name[:-1] args = "".join(str(z) for z in args) diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 539f1a477..59a18797b 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -33,7 +33,7 @@ class Sample(object): def banner(s): if trace: - print(f"\n{g._callerName(2)}: ===== {s}\n") + print(f"\n{g._caller_name(2)}: ===== {s}\n") if trace: print('') From c2d0533c34a626445180199d8bca5cc3f644eb10 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 2 Feb 2023 08:26:07 -0600 Subject: [PATCH 47/99] Rename debug_utils to tracing_utils --- rope/base/utils/{debug_utils.py => tracing_utils.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename rope/base/utils/{debug_utils.py => tracing_utils.py} (100%) diff --git a/rope/base/utils/debug_utils.py b/rope/base/utils/tracing_utils.py similarity index 100% rename from rope/base/utils/debug_utils.py rename to rope/base/utils/tracing_utils.py From 91034ada67a5a40aeb7e6038e6266752d6337d07 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 2 Feb 2023 08:29:28 -0600 Subject: [PATCH 48/99] Complete the renaming --- rope/base/pynames.py | 2 +- rope/base/pyobjects.py | 2 +- rope/base/pyobjectsdef.py | 2 +- rope/base/pyscopes.py | 2 +- rope/base/utils/__init__.py | 2 +- ropetest/objectinfertest.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 91eb10b23..5164ab90e 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -10,7 +10,7 @@ from rope.base import pyobjectsdef -from rope.base.utils import debug_utils as g ### +from rope.base.utils import tracing_utils as g ### assert g ### diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 956bc88ec..cf60e500a 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -2,7 +2,7 @@ from rope.base import ast, exceptions, utils -from rope.base.utils import debug_utils as g ### +from rope.base.utils import tracing_utils as g ### assert g ### diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 08d486eec..d1c16a291 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -15,7 +15,7 @@ utils, ) -from rope.base.utils import debug_utils as g ### +from rope.base.utils import tracing_utils as g ### assert g ### diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index f69519007..c7e9fe392 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -2,7 +2,7 @@ from rope.base import ast, codeanalyze, exceptions, pynames, utils from rope.refactor import patchedast -from rope.base.utils import debug_utils as g ### +from rope.base.utils import tracing_utils as g ### assert g ### diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index a764b5715..8d507bfb4 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -1,7 +1,7 @@ import sys import warnings -from rope.base.utils import debug_utils as g +from rope.base.utils import tracing_utils as g assert g ### diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 59a18797b..0cdb49dab 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -5,7 +5,7 @@ from rope.base import libutils from ropetest import testutils -from rope.base.utils import debug_utils as g ### +from rope.base.utils import tracing_utils as g ### assert g ### class ObjectInferTest(unittest.TestCase): From 2c1d6a224358835822b75774994ce902647d4a16 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 2 Feb 2023 08:46:36 -0600 Subject: [PATCH 49/99] Revert to @saveit --- rope/base/utils/__init__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 8d507bfb4..783d59310 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -6,7 +6,7 @@ assert g ### -def inject(func): +def saveit(func): """ A decorator that injects a singleton ivar (in self) if the ivar does not already exist. @@ -34,7 +34,7 @@ def _wrapper(self, *args, **kwargs): else: def _wrapper(self, *args, **kwargs): - tag = "@inject" + tag = "@saveit" if not hasattr(self, ivar_name): # Instantiate the object. obj = func(self, *args, **kwargs) @@ -58,8 +58,7 @@ def _wrapper(self, *args, **kwargs): return _wrapper -cacheit = inject -saveit = inject +cacheit = saveit def prevent_recursion(default): From 288168b4fad8c47ca8c47301972823995609bf70 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 2 Feb 2023 08:57:48 -0600 Subject: [PATCH 50/99] Remove unimportant ### comments --- rope/base/pynames.py | 4 ++-- rope/base/pyobjects.py | 4 ++-- rope/base/pyobjectsdef.py | 6 +++--- rope/base/pyscopes.py | 4 ++-- rope/base/utils/__init__.py | 2 +- ropetest/objectinfertest.py | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 5164ab90e..34bd23517 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -10,9 +10,9 @@ from rope.base import pyobjectsdef -from rope.base.utils import tracing_utils as g ### +from rope.base.utils import tracing_utils as g -assert g ### +assert g class PyName: diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index cf60e500a..a68a2ceb5 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -2,9 +2,9 @@ from rope.base import ast, exceptions, utils -from rope.base.utils import tracing_utils as g ### +from rope.base.utils import tracing_utils as g -assert g ### +assert g class PyObject: diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index d1c16a291..83962c65e 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -15,9 +15,9 @@ utils, ) -from rope.base.utils import tracing_utils as g ### +from rope.base.utils import tracing_utils as g -assert g ### +assert g class PyFunction(pyobjects.PyFunction): @@ -591,7 +591,7 @@ def _get_pyobject(self, node): class _GlobalVisitor(_ScopeVisitor): - pass ### + pass ### # def __init__(self, pycore, owner_object): # super().__init__(pycore, owner_object) diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index c7e9fe392..322209974 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -2,9 +2,9 @@ from rope.base import ast, codeanalyze, exceptions, pynames, utils from rope.refactor import patchedast -from rope.base.utils import tracing_utils as g ### +from rope.base.utils import tracing_utils as g -assert g ### +assert g class Scope: diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index 783d59310..a4b8974ea 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -3,7 +3,7 @@ from rope.base.utils import tracing_utils as g -assert g ### +assert g def saveit(func): diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 0cdb49dab..2ac28eee2 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -5,8 +5,8 @@ from rope.base import libutils from ropetest import testutils -from rope.base.utils import tracing_utils as g ### -assert g ### +from rope.base.utils import tracing_utils as g +assert g class ObjectInferTest(unittest.TestCase): def setUp(self): @@ -68,7 +68,7 @@ def banner(s): # scope is a GlobalScope. It might be any subclass of Scope. # scope.pyobject is a pyobjectsdef.PyModule. - ### if trace: g.trace('*** scope.pyobject', scope.pyobject) + # if trace: g.trace('*** scope.pyobject', scope.pyobject) # *** Calling scope["Sample"] (via _ScopeVisitor._ClassDef) # instantiates pyobjects.PyClass *and* pyobjectsdef.PyClass. From 230436258a737a5187cf51b27444057b78e43df2 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 2 Feb 2023 09:10:30 -0600 Subject: [PATCH 51/99] Add annotations for do-nothing methods! --- rope/base/pynames.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 34bd23517..ca9629de1 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -6,9 +6,10 @@ from rope.base import exceptions, utils if typing.TYPE_CHECKING: - from typing import Union + from typing import Any, Tuple, Union from rope.base import pyobjectsdef + from rope.base.pyobjects import PyObject from rope.base.utils import tracing_utils as g @@ -18,11 +19,13 @@ class PyName: """References to `PyObject` inside python programs""" - def get_object(self): + def get_object(self) -> PyObject: """Return the `PyObject` object referenced by this `PyName`""" + return None - def get_definition_location(self): + def get_definition_location(self) -> Tuple[Any, int]: """Return a (module, lineno) tuple""" + return None class DefinedName(PyName): From fe91ab88f8cf994ec487008a4e2d76e4df1d9467 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 2 Feb 2023 09:21:29 -0600 Subject: [PATCH 52/99] Fix recent annotations --- rope/base/pynames.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index ca9629de1..2a1627db9 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -6,7 +6,7 @@ from rope.base import exceptions, utils if typing.TYPE_CHECKING: - from typing import Any, Tuple, Union + from typing import Any, Optional, Tuple, Union from rope.base import pyobjectsdef from rope.base.pyobjects import PyObject @@ -19,11 +19,11 @@ class PyName: """References to `PyObject` inside python programs""" - def get_object(self) -> PyObject: + def get_object(self) -> Optional[PyObject]: """Return the `PyObject` object referenced by this `PyName`""" return None - def get_definition_location(self) -> Tuple[Any, int]: + def get_definition_location(self) -> Optional[Tuple[Any, int]]: """Return a (module, lineno) tuple""" return None From 8d7bb77292cd307fc337341608d68cfcdf347382 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 2 Feb 2023 13:05:13 -0600 Subject: [PATCH 53/99] Eliminate ### and faux generality --- rope/base/pynames.py | 4 ++-- rope/base/pyobjects.py | 4 ++-- rope/base/pyobjectsdef.py | 7 ++----- rope/base/utils/tracing_utils.py | 4 ---- ropetest/objectinfertest.py | 1 - 5 files changed, 6 insertions(+), 14 deletions(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 2a1627db9..7194cda6b 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -194,9 +194,9 @@ def get_definition_location(self): def _get_concluded_data(module): if module is None: - g.trace("(*** pynames function): instantiate") ### + g.trace("(*** pynames function): instantiate") return rope.base.pyobjects._ConcludedData() - if 0: ### + if 0: # Callers... # test_simple_type_inferencing,__getitem__,get_name,__getitem__, # get_attribute,newfunc,_get_structural_attributes,_create_structural_attributes, diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index a68a2ceb5..eb24248e3 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -175,7 +175,7 @@ def __init__(self, pycore, ast_node, parent): self.concluded_attributes = self.get_module()._get_concluded_data() self.attributes = self.get_module()._get_concluded_data() self.defineds = None - if g.trace_ctors: ### + if 0: g.trace( f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", g.callers(), @@ -312,7 +312,7 @@ def __init__(self, pycore, ast_node, resource): self.concluded_data = [] AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) - if g.trace_ctors: ### + if 0: g.trace( f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", g.callers(), diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 83962c65e..0bc222a8b 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -137,7 +137,7 @@ def __init__(self, pycore, ast_node, parent): rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent) self.parent = parent self._superclasses = self.get_module()._get_concluded_data() - if g.trace_ctors: ### + if 0: g.trace(f"{g.get_ctor_name(self, __file__)} {' ':14}", g.callers()) def get_superclasses(self): @@ -188,7 +188,7 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.star_imports = [] self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) - if g.trace_ctors: ### + if 0: g.trace(f"{g.get_ctor_name(self, __file__)} {' ':14}", g.callers()) super().__init__(pycore, node, resource) @@ -592,9 +592,6 @@ def _get_pyobject(self, node): class _GlobalVisitor(_ScopeVisitor): pass - ### - # def __init__(self, pycore, owner_object): - # super().__init__(pycore, owner_object) class _ClassVisitor(_ScopeVisitor): diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index a0fd9b844..90582f5b2 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -9,10 +9,6 @@ import sys from typing import Any, List -trace_ctors = False # For traces in various ctors. -visitor_trace_list: List[str] = None # List of visitors to trace. -ctor_trace_list: List[str] = None # List of ctors to trace. - def _caller_name(n: int) -> str: try: diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 2ac28eee2..5d9dba5fe 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -16,7 +16,6 @@ def setUp(self): """ super().setUp() self.project = testutils.sample_project() - g.trace_ctors = False ### def tearDown(self): testutils.remove_project(self.project) From dca8e55a10b7da84a81d773e21215deee630d569 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 2 Feb 2023 13:11:37 -0600 Subject: [PATCH 54/99] Add trace to RopeNodeVisitor.visit --- rope/base/ast.py | 6 ++++++ ropetest/objectinfertest.py | 1 + 2 files changed, 7 insertions(+) diff --git a/rope/base/ast.py b/rope/base/ast.py index 3aff82699..d6ca71ddf 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -4,6 +4,10 @@ from rope.base import fscommands +from rope.base.utils import tracing_utils as g + +assert g + try: from ast import _const_node_type_names except ImportError: @@ -58,8 +62,10 @@ def call_for_nodes(node, callback): class RopeNodeVisitor(ast.NodeVisitor): + # This is the only visit method in Rope. def visit(self, node): """Modified from ast.NodeVisitor to match rope's existing Visitor implementation""" + g.trace(node.__class__.__name__, g.callers()) method = "_" + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) return visitor(node) diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 5d9dba5fe..821d2bc3a 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -6,6 +6,7 @@ from ropetest import testutils from rope.base.utils import tracing_utils as g + assert g class ObjectInferTest(unittest.TestCase): From 8593547a3fbe8df0c16ec4b47f7d91fb2701ef76 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 2 Feb 2023 13:14:41 -0600 Subject: [PATCH 55/99] Improve trace. Fix g.trace --- rope/base/ast.py | 2 +- rope/base/utils/tracing_utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rope/base/ast.py b/rope/base/ast.py index d6ca71ddf..a8e125b92 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -65,7 +65,7 @@ class RopeNodeVisitor(ast.NodeVisitor): # This is the only visit method in Rope. def visit(self, node): """Modified from ast.NodeVisitor to match rope's existing Visitor implementation""" - g.trace(node.__class__.__name__, g.callers()) + g.trace(f"{node.__class__.__name__:>10}:", g.callers()) method = "_" + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) return visitor(node) diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index 90582f5b2..5fdae1f8a 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -126,5 +126,5 @@ def trace(*args: Any) -> None: name = _caller_name(2) if name.endswith(".pyc"): name = name[:-1] - args = "".join(str(z) for z in args) + args = " ".join(str(z) for z in args) print(f"{name} {args}") From 6df2dcf73e935721acda81a9a1bffd2892f38771 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 2 Feb 2023 16:33:58 -0600 Subject: [PATCH 56/99] Improve tracing of ast.RopeNodeVisitor.visit --- rope/base/ast.py | 5 ++++- rope/base/utils/tracing_utils.py | 8 ++++---- ropetest/objectinfertest.py | 16 ++++++++-------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/rope/base/ast.py b/rope/base/ast.py index a8e125b92..2ae914f55 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -65,9 +65,12 @@ class RopeNodeVisitor(ast.NodeVisitor): # This is the only visit method in Rope. def visit(self, node): """Modified from ast.NodeVisitor to match rope's existing Visitor implementation""" - g.trace(f"{node.__class__.__name__:>10}:", g.callers()) method = "_" + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) + if 1: + module, name = visitor.__module__, visitor.__name__ + if name != "generic_visit": + g.trace(f"{module:>25}.{name:<10}", g.callers()) return visitor(node) diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index 5fdae1f8a..1d8f1c795 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -13,10 +13,10 @@ def _caller_name(n: int) -> str: try: # Get the function name from the call stack. - f1 = sys._getframe(n) # The stack frame, n levels up. - code1 = f1.f_code # The code object - locals_ = f1.f_locals # The local namespace. - name = code1.co_name + frame = sys._getframe(n) # The stack frame, n levels up. + code = frame.f_code # The code object + locals_ = frame.f_locals # The local namespace. + name = code.co_name obj = locals_.get("self") if obj and name == "__init__": return f"{obj.__class__.__name__}.{name}" diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 821d2bc3a..5f838122b 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -30,14 +30,13 @@ class Sample(object): """) trace = True # Set to False when running all tests. + + if trace: + print('') def banner(s): if trace: - print(f"\n{g._caller_name(2)}: ===== {s}\n") - - if trace: - print('') - g.trace_ctors = True # True: Enable tracing in ctors. + print(f"\n{g._caller_name(2)}: ===== {s}") banner('after setUp') @@ -63,7 +62,7 @@ def banner(s): scope = libutils.get_string_scope(self.project, code) - banner('after get_string_scope') + banner('after get_string_scope\n') # scope is a GlobalScope. It might be any subclass of Scope. # scope.pyobject is a pyobjectsdef.PyModule. @@ -77,7 +76,7 @@ def banner(s): sample_class = scope["Sample"].get_object() - banner('after sample_class = scope["Sample"].get_object()') + banner('after sample_class = scope["Sample"].get_object()\n') # sample_class is a pyobjectsdef.PyClass ("::Sample" at ...) @@ -93,7 +92,8 @@ def banner(s): # scope["a_var"].pyobject is a pynames._Inferred. # scope["a_var"].get_object() is a pyobjects.PyObject. - if trace: print(f"sample_class: {sample_class}") + if trace: + print(f"\nsample_class: {sample_class}") self.assertEqual(sample_class, a_var.get_type()) def test_simple_type_inferencing_classes_defined_in_holding_scope(self): From 34b2af842614876c949f701d7bb38aa90d888a31 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 3 Feb 2023 02:00:21 -0600 Subject: [PATCH 57/99] Improve docstrings --- rope/base/utils/tracing_utils.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index 1d8f1c795..a1f94513b 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -11,6 +11,7 @@ def _caller_name(n: int) -> str: + """Return the name of the caller n levels back in the call stack.""" try: # Get the function name from the call stack. frame = sys._getframe(n) # The stack frame, n levels up. @@ -30,7 +31,7 @@ def _caller_name(n: int) -> str: def caller(i: int = 1) -> str: - """Return the caller name i levels up the stack.""" + """Return the caller name i levels up the call stack.""" return callers(i + 1).split(",")[0] @@ -71,7 +72,7 @@ def callers_list(n: int = 4) -> List[str]: def get_ctor_name(self: Any, file_name: str, width: int = 25): - """Return .:>width""" + """Return . padded to the given width.""" class_name = self.__class__.__name__ module_name = short_file_name(file_name).replace(".py", "") combined_name = f"{module_name}.{class_name}" @@ -102,8 +103,10 @@ def split_lines(s: str) -> List[str]: """ Split s into lines, preserving the number of lines and the endings of all lines, including the last line. + + This function is not the same as s.splitlines(True). """ - return s.splitlines(True) if s else [] # This is a Python string function! + return s.splitlines(True) if s else [] def to_string(obj: Any, indent: int = 0, tag: str = None, width: int = 120) -> str: From 5dc69a16387003a858ae1924e156ce28e738e498 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 3 Feb 2023 16:48:13 -0600 Subject: [PATCH 58/99] Fix mypy complaints --- rope/base/utils/tracing_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index a1f94513b..468015286 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -71,7 +71,7 @@ def callers_list(n: int = 4) -> List[str]: return list(reversed(result)) -def get_ctor_name(self: Any, file_name: str, width: int = 25): +def get_ctor_name(self: Any, file_name: str, width: int = 25) -> str: """Return . padded to the given width.""" class_name = self.__class__.__name__ module_name = short_file_name(file_name).replace(".py", "") @@ -129,5 +129,5 @@ def trace(*args: Any) -> None: name = _caller_name(2) if name.endswith(".pyc"): name = name[:-1] - args = " ".join(str(z) for z in args) - print(f"{name} {args}") + args_s = " ".join(str(z) for z in args) + print(f"{name} {args_s}") From 70d428525b067196d70869fe8755521da032b67c Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Mon, 6 Feb 2023 07:02:55 -0600 Subject: [PATCH 59/99] Remove (again) two pyflakes complaints --- rope/base/oi/type_hinting/providers/pep0484_type_comments.py | 2 +- rope/contrib/autoimport/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rope/base/oi/type_hinting/providers/pep0484_type_comments.py b/rope/base/oi/type_hinting/providers/pep0484_type_comments.py index d33566540..dacc071e8 100644 --- a/rope/base/oi/type_hinting/providers/pep0484_type_comments.py +++ b/rope/base/oi/type_hinting/providers/pep0484_type_comments.py @@ -1,6 +1,6 @@ import re -from rope.base.oi.type_hinting import utils +# from rope.base.oi.type_hinting import utils from rope.base.oi.type_hinting.providers import interfaces diff --git a/rope/contrib/autoimport/__init__.py b/rope/contrib/autoimport/__init__.py index 65459cef4..776cc5156 100644 --- a/rope/contrib/autoimport/__init__.py +++ b/rope/contrib/autoimport/__init__.py @@ -1,6 +1,6 @@ """AutoImport module for rope.""" from .pickle import AutoImport as _PickleAutoImport -from .sqlite import AutoImport as _SqliteAutoImport +# from .sqlite import AutoImport as _SqliteAutoImport AutoImport = _PickleAutoImport From 74424fb4fa601fb6f60b034e1541d4ec98163ba0 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Mon, 6 Feb 2023 07:46:34 -0600 Subject: [PATCH 60/99] Add doc files --- docs/index.rst | 1 + docs/theory.rst | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 docs/theory.rst diff --git a/docs/index.rst b/docs/index.rst index f56f81809..70b269b4b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -15,6 +15,7 @@ Welcome to rope's documentation! library configuration contributing + theory release-process dev/issues diff --git a/docs/theory.rst b/docs/theory.rst new file mode 100644 index 000000000..dd96a6b3e --- /dev/null +++ b/docs/theory.rst @@ -0,0 +1,57 @@ +.. rst3: filename: docs/theory + +.. _`python's ast module`: https://docs.python.org/3/library/ast.html + +===================== +How Rope infers types +===================== + +This is the Theory of Operation for Rope's type inference, +the most complex part of Rope. + +Only Rope's core devs need to understand this material. + +Some familiarity with `Python's ast module`_ is recommended, but not essential. + +.. contents:: Table of Contents + +Why Rope must infer types +------------------------- + +.. To do. + +Overview of Rope's code base +---------------------------- + +- Startup code. +- Type inference code. +- Utility code. +- Refactoring code. +- Code completion. + +Overview of type inference +-------------------------- + + +First principles: +- Traversers do most of the work. +- Local inference is easy; global inference is hard. + +Learning what to ignore is important. +- @saveit is part of Rope's startup code. It has no direct part in type inference. + +What *not* to ignore: +- @prevent_recursion prevents endless inference loops. + +What is an inference? ++++++++++++++++++++++ + +Further study +------------- + +Deep study of a few unit tests is recommended. + +`ObjectInferTest.test_simple_type_inferencing` is a good place to start. + +.. --- Insert traces here --- + From 6a3f491656107226e0b43cb9493fae571a724e7d Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Mon, 6 Feb 2023 08:54:55 -0600 Subject: [PATCH 61/99] blacken --- rope/contrib/autoimport/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rope/contrib/autoimport/__init__.py b/rope/contrib/autoimport/__init__.py index 776cc5156..4e327241d 100644 --- a/rope/contrib/autoimport/__init__.py +++ b/rope/contrib/autoimport/__init__.py @@ -1,5 +1,6 @@ """AutoImport module for rope.""" from .pickle import AutoImport as _PickleAutoImport + # from .sqlite import AutoImport as _SqliteAutoImport AutoImport = _PickleAutoImport From 46f3c95609730de1e8dd13b2c99394fb5f5b79ba Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 8 Feb 2023 14:31:12 -0600 Subject: [PATCH 62/99] Simplify traces with g.format --- rope/base/ast.py | 2 +- rope/base/pynames.py | 8 ++++++++ rope/base/pyobjects.py | 9 +++------ rope/base/pyobjectsdef.py | 4 ++-- rope/base/utils/tracing_utils.py | 10 +++------- ropetest/objectinfertest.py | 4 ++-- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/rope/base/ast.py b/rope/base/ast.py index 2ae914f55..9c23d3f8a 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -70,7 +70,7 @@ def visit(self, node): if 1: module, name = visitor.__module__, visitor.__name__ if name != "generic_visit": - g.trace(f"{module:>25}.{name:<10}", g.callers()) + print(g.format("visit", module, name), g.callers()) return visitor(node) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 7194cda6b..117554a34 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -19,6 +19,12 @@ class PyName: """References to `PyObject` inside python programs""" + if 1: # Temp ctor. + + def __init__(self): + g.trace('*****') ### Not called in basic test. + print(g.format("__init__", self.__module__), g.callers()) + def get_object(self) -> Optional[PyObject]: """Return the `PyObject` object referenced by this `PyName`""" return None @@ -31,6 +37,8 @@ def get_definition_location(self) -> Optional[Tuple[Any, int]]: class DefinedName(PyName): def __init__(self, pyobject): self.pyobject = pyobject + if 1: + print(g.format("__init__", self.__module__, "DefinedName"), g.callers()) def get_object(self): return self.pyobject diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index eb24248e3..f6fd7ab46 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -176,8 +176,8 @@ def __init__(self, pycore, ast_node, parent): self.attributes = self.get_module()._get_concluded_data() self.defineds = None if 0: - g.trace( - f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", + print( + g.format("__init__", self.__module__, ast_node.__class__.__name__), g.callers(), ) @@ -313,10 +313,7 @@ def __init__(self, pycore, ast_node, resource): AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) if 0: - g.trace( - f"{g.get_ctor_name(self, __file__)} {ast_node.__class__.__name__:14}", - g.callers(), - ) + print(g.format("__init__", self.__module__), g.callers()) @property def absolute_name(self) -> str: diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index abd8b8608..48cb64544 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -138,7 +138,7 @@ def __init__(self, pycore, ast_node, parent): self.parent = parent self._superclasses = self.get_module()._get_concluded_data() if 0: - g.trace(f"{g.get_ctor_name(self, __file__)} {' ':14}", g.callers()) + print(g.format("__init__", self.__module__), g.callers()) def get_superclasses(self): if self._superclasses.get() is None: @@ -189,7 +189,7 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) if 0: - g.trace(f"{g.get_ctor_name(self, __file__)} {' ':14}", g.callers()) + print(g.format("__init__", self.__module__), g.callers()) super().__init__(pycore, node, resource) def _init_source(self, pycore, source_code, resource): diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index 468015286..34900e8bc 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -71,13 +71,9 @@ def callers_list(n: int = 4) -> List[str]: return list(reversed(result)) -def get_ctor_name(self: Any, file_name: str, width: int = 25) -> str: - """Return . padded to the given width.""" - class_name = self.__class__.__name__ - module_name = short_file_name(file_name).replace(".py", "") - combined_name = f"{module_name}.{class_name}" - padding = " " * max(0, 25 - len(combined_name)) - return f"{padding}{combined_name}" +def format(caller: str, module: str, function: str = "") -> str: + """Format call, module and optional function, aligned for traces.""" + return f"{caller:<10} {module:>25}.{function:<15}" def plural(obj: Any) -> str: diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 5f838122b..97066951b 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -38,7 +38,6 @@ def banner(s): if trace: print(f"\n{g._caller_name(2)}: ===== {s}") - banner('after setUp') # 1. setUp creates self.project. @@ -93,7 +92,8 @@ def banner(s): # scope["a_var"].get_object() is a pyobjects.PyObject. if trace: - print(f"\nsample_class: {sample_class}") + print('') + print(f"sample_class: {sample_class}") self.assertEqual(sample_class, a_var.get_type()) def test_simple_type_inferencing_classes_defined_in_holding_scope(self): From 98e3e1f2e9dcb4137ce97f062da4b7d65afbec10 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 8 Feb 2023 14:32:29 -0600 Subject: [PATCH 63/99] Blacken --- rope/base/pynames.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 117554a34..2fcf6144f 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -22,7 +22,7 @@ class PyName: if 1: # Temp ctor. def __init__(self): - g.trace('*****') ### Not called in basic test. + g.trace("*****") ### Not called in basic test. print(g.format("__init__", self.__module__), g.callers()) def get_object(self) -> Optional[PyObject]: From a89df6bd569f199fa808d3773a2886fa312a17d2 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 8 Feb 2023 15:09:11 -0600 Subject: [PATCH 64/99] Add format_ctor and use it --- rope/base/pynames.py | 2 +- rope/base/pyobjects.py | 11 ++++------- rope/base/pyobjectsdef.py | 8 ++++---- rope/base/utils/tracing_utils.py | 13 ++++++++++--- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 2fcf6144f..c0cba33e6 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -38,7 +38,7 @@ class DefinedName(PyName): def __init__(self, pyobject): self.pyobject = pyobject if 1: - print(g.format("__init__", self.__module__, "DefinedName"), g.callers()) + print(g.format_ctor(self), g.callers(2)) def get_object(self): return self.pyobject diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index f6fd7ab46..a772bc19c 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -175,11 +175,8 @@ def __init__(self, pycore, ast_node, parent): self.concluded_attributes = self.get_module()._get_concluded_data() self.attributes = self.get_module()._get_concluded_data() self.defineds = None - if 0: - print( - g.format("__init__", self.__module__, ast_node.__class__.__name__), - g.callers(), - ) + if 1: + print(g.format_ctor(self), g.callers(2)) def __repr__(self): return '<{}.{} "{}" at {}>'.format( @@ -312,8 +309,8 @@ def __init__(self, pycore, ast_node, resource): self.concluded_data = [] AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) - if 0: - print(g.format("__init__", self.__module__), g.callers()) + if 1: + print(g.format_ctor(self), g.callers(2)) @property def absolute_name(self) -> str: diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 48cb64544..6b4e57861 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -137,8 +137,8 @@ def __init__(self, pycore, ast_node, parent): rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent) self.parent = parent self._superclasses = self.get_module()._get_concluded_data() - if 0: - print(g.format("__init__", self.__module__), g.callers()) + if 1: + print(g.format_ctor(self), g.callers(2)) def get_superclasses(self): if self._superclasses.get() is None: @@ -188,8 +188,8 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.star_imports = [] self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) - if 0: - print(g.format("__init__", self.__module__), g.callers()) + if 1: + print(g.format_ctor(self), g.callers(2)) super().__init__(pycore, node, resource) def _init_source(self, pycore, source_code, resource): diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index 34900e8bc..ac5c3d7ba 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -71,9 +71,16 @@ def callers_list(n: int = 4) -> List[str]: return list(reversed(result)) -def format(caller: str, module: str, function: str = "") -> str: - """Format call, module and optional function, aligned for traces.""" - return f"{caller:<10} {module:>25}.{function:<15}" +def format(caller_name: str, module: str, function: str = "") -> str: + """Format caller_name, module and optional function, aligned for traces.""" + module_s = module.replace("rope.base.", "") + return f"{caller_name:>10} {module_s:>15}.{function:<15}" + + +def format_ctor(self: Any) -> str: + class_s = self.__class__.__name__ + module_s = self.__module__.replace("rope.base.", "") + return f"{'__init__':>10} {module_s:>15}.{class_s:<15}" def plural(obj: Any) -> str: From 57315e38860b5cc12da3ed7c677065acebac303b Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 8 Feb 2023 15:26:18 -0600 Subject: [PATCH 65/99] Improve traces --- rope/base/ast.py | 2 +- rope/base/pynames.py | 2 +- rope/base/pyobjects.py | 4 ++-- rope/base/pyobjectsdef.py | 4 ++-- ropetest/objectinfertest.py | 30 ++++++++++++++---------------- 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/rope/base/ast.py b/rope/base/ast.py index 9c23d3f8a..531e59136 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -70,7 +70,7 @@ def visit(self, node): if 1: module, name = visitor.__module__, visitor.__name__ if name != "generic_visit": - print(g.format("visit", module, name), g.callers()) + print(g.format("visit", module, name), g.callers(4)) return visitor(node) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index c0cba33e6..adb01f4b8 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -38,7 +38,7 @@ class DefinedName(PyName): def __init__(self, pyobject): self.pyobject = pyobject if 1: - print(g.format_ctor(self), g.callers(2)) + print(g.format_ctor(self), g.callers(4)) def get_object(self): return self.pyobject diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index a772bc19c..12b91f9dc 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -176,7 +176,7 @@ def __init__(self, pycore, ast_node, parent): self.attributes = self.get_module()._get_concluded_data() self.defineds = None if 1: - print(g.format_ctor(self), g.callers(2)) + print(g.format_ctor(self), g.callers(4)) def __repr__(self): return '<{}.{} "{}" at {}>'.format( @@ -310,7 +310,7 @@ def __init__(self, pycore, ast_node, resource): AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) if 1: - print(g.format_ctor(self), g.callers(2)) + print(g.format_ctor(self), g.callers(4)) @property def absolute_name(self) -> str: diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 6b4e57861..4eb698b7e 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -138,7 +138,7 @@ def __init__(self, pycore, ast_node, parent): self.parent = parent self._superclasses = self.get_module()._get_concluded_data() if 1: - print(g.format_ctor(self), g.callers(2)) + print(g.format_ctor(self), g.callers(4)) def get_superclasses(self): if self._superclasses.get() is None: @@ -189,7 +189,7 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) if 1: - print(g.format_ctor(self), g.callers(2)) + print(g.format_ctor(self), g.callers(4)) super().__init__(pycore, node, resource) def _init_source(self, pycore, source_code, resource): diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 97066951b..c7e94aa4f 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -29,16 +29,10 @@ class Sample(object): a_var = Sample() """) - trace = True # Set to False when running all tests. - - if trace: - print('') - - def banner(s): - if trace: - print(f"\n{g._caller_name(2)}: ===== {s}") - - banner('after setUp') + print('') + print('') + print('after: setUp') + print('before: get_string_scope\n') # 1. setUp creates self.project. @@ -61,7 +55,9 @@ def banner(s): scope = libutils.get_string_scope(self.project, code) - banner('after get_string_scope\n') + print('') + print('after: get_string_scope') + print('before: sample_class = scope["Sample"].get_object()\n') # scope is a GlobalScope. It might be any subclass of Scope. # scope.pyobject is a pyobjectsdef.PyModule. @@ -75,14 +71,18 @@ def banner(s): sample_class = scope["Sample"].get_object() - banner('after sample_class = scope["Sample"].get_object()\n') - + print('') + print('after: sample_class = scope["Sample"].get_object()') + print('before: a_var = scope["a_var"].get_object()\n') # sample_class is a pyobjectsdef.PyClass ("::Sample" at ...) # scope["Sample"] is a DefinedName. # scope["Sample"].pyobject is a pyobjectsdef.PyClass. a_var = scope["a_var"].get_object() + + print('') + print('after: a_var = scope["a_var"].get_object()\n') # a_var is a pyobjects.PyObject # a_var.get_type() is a pyobjectsdef.PyClass ("::Sample" at ...) @@ -91,9 +91,7 @@ def banner(s): # scope["a_var"].pyobject is a pynames._Inferred. # scope["a_var"].get_object() is a pyobjects.PyObject. - if trace: - print('') - print(f"sample_class: {sample_class}") + print(f"sample_class: {sample_class}") self.assertEqual(sample_class, a_var.get_type()) def test_simple_type_inferencing_classes_defined_in_holding_scope(self): From 4d33fd50a039744bf7f0425ec2b028c3a5756aa7 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 8 Feb 2023 15:49:50 -0600 Subject: [PATCH 66/99] Add g.align and use it --- rope/base/pynames.py | 2 +- rope/base/pyobjects.py | 4 ++-- rope/base/pyobjectsdef.py | 10 ++++++++-- rope/base/utils/tracing_utils.py | 13 +++++++++---- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index adb01f4b8..86837c10c 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -38,7 +38,7 @@ class DefinedName(PyName): def __init__(self, pyobject): self.pyobject = pyobject if 1: - print(g.format_ctor(self), g.callers(4)) + print(g.format_ctor(self, __file__), g.callers(4)) def get_object(self): return self.pyobject diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 12b91f9dc..9a9f24f29 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -176,7 +176,7 @@ def __init__(self, pycore, ast_node, parent): self.attributes = self.get_module()._get_concluded_data() self.defineds = None if 1: - print(g.format_ctor(self), g.callers(4)) + print(g.format_ctor(self, __file__), g.callers(4)) def __repr__(self): return '<{}.{} "{}" at {}>'.format( @@ -310,7 +310,7 @@ def __init__(self, pycore, ast_node, resource): AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) if 1: - print(g.format_ctor(self), g.callers(4)) + print(g.format_ctor(self, __file__), g.callers(4)) @property def absolute_name(self) -> str: diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 4eb698b7e..ad6bb4fce 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -138,7 +138,7 @@ def __init__(self, pycore, ast_node, parent): self.parent = parent self._superclasses = self.get_module()._get_concluded_data() if 1: - print(g.format_ctor(self), g.callers(4)) + print(g.format_ctor(self, __file__), g.callers(4)) def get_superclasses(self): if self._superclasses.get() is None: @@ -189,7 +189,7 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) if 1: - print(g.format_ctor(self), g.callers(4)) + print(g.format_ctor(self, __file__), g.callers(4)) super().__init__(pycore, node, resource) def _init_source(self, pycore, source_code, resource): @@ -423,10 +423,16 @@ def get_module(self): def _ClassDef(self, node): pyclass = PyClass(self.pycore, node, self.owner_object) self.names[node.name] = pynamesdef.DefinedName(pyclass) + if 1: + print(g.align("_ScopeVisitor", "_ClassDef"), node.name) self.defineds.append(pyclass) def _FunctionDef(self, node): pyfunction = PyFunction(self.pycore, node, self.owner_object) + + if 1: + print(g.align("_ScopeVisitor", "_FunctionDef"), node.name) + for decorator in pyfunction.decorators: if isinstance(decorator, ast.Name) and decorator.id == "property": if isinstance(self, _ClassVisitor): diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index ac5c3d7ba..2deac21d0 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -71,16 +71,21 @@ def callers_list(n: int = 4) -> List[str]: return list(reversed(result)) +def align(s1: str, s2) -> str: + return f"{' ':10} {s1:>16}.{s2:<15}" + + def format(caller_name: str, module: str, function: str = "") -> str: """Format caller_name, module and optional function, aligned for traces.""" module_s = module.replace("rope.base.", "") - return f"{caller_name:>10} {module_s:>15}.{function:<15}" + return f"{caller_name:>10} {module_s:>16}.{function:<15}" -def format_ctor(self: Any) -> str: +def format_ctor(self: Any, file_name: str) -> str: class_s = self.__class__.__name__ - module_s = self.__module__.replace("rope.base.", "") - return f"{'__init__':>10} {module_s:>15}.{class_s:<15}" + # file_name_s = file_name.replace("rope.base.", "") + file_name_s = short_file_name(file_name) + return f"{'__init__':>10} {file_name_s:>16}.{class_s:<15}" def plural(obj: Any) -> str: From 8d71ccdfbbda1d6fe84d0b8430be3fb9baa2a9a7 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 8 Feb 2023 16:52:12 -0600 Subject: [PATCH 67/99] format_ctor takes an explit class name. Previous code gave unexpected results --- rope/base/ast.py | 2 +- rope/base/pynames.py | 4 ++-- rope/base/pyobjects.py | 4 ++-- rope/base/pyobjectsdef.py | 10 ++++++---- rope/base/utils/tracing_utils.py | 13 +++++++------ 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/rope/base/ast.py b/rope/base/ast.py index 531e59136..b4d3c0510 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -70,7 +70,7 @@ def visit(self, node): if 1: module, name = visitor.__module__, visitor.__name__ if name != "generic_visit": - print(g.format("visit", module, name), g.callers(4)) + print(g.format("visit", module, name)) return visitor(node) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 86837c10c..b0c0c2890 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -23,7 +23,7 @@ class PyName: def __init__(self): g.trace("*****") ### Not called in basic test. - print(g.format("__init__", self.__module__), g.callers()) + print(g.format_ctor("PyName", __file__)) def get_object(self) -> Optional[PyObject]: """Return the `PyObject` object referenced by this `PyName`""" @@ -38,7 +38,7 @@ class DefinedName(PyName): def __init__(self, pyobject): self.pyobject = pyobject if 1: - print(g.format_ctor(self, __file__), g.callers(4)) + print(g.format_ctor("DefinedName", __file__), repr(pyobject)) def get_object(self): return self.pyobject diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 9a9f24f29..33ddd8387 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -176,7 +176,7 @@ def __init__(self, pycore, ast_node, parent): self.attributes = self.get_module()._get_concluded_data() self.defineds = None if 1: - print(g.format_ctor(self, __file__), g.callers(4)) + print(g.format_ctor("DefinedObject", __file__), ast_node) def __repr__(self): return '<{}.{} "{}" at {}>'.format( @@ -310,7 +310,7 @@ def __init__(self, pycore, ast_node, resource): AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) if 1: - print(g.format_ctor(self, __file__), g.callers(4)) + print(g.format_ctor("PyModule", __file__)) @property def absolute_name(self) -> str: diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index ad6bb4fce..49dcd6f61 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -138,7 +138,7 @@ def __init__(self, pycore, ast_node, parent): self.parent = parent self._superclasses = self.get_module()._get_concluded_data() if 1: - print(g.format_ctor(self, __file__), g.callers(4)) + print(g.format_ctor("PyClass", __file__), ast_node.name) def get_superclasses(self): if self._superclasses.get() is None: @@ -189,7 +189,7 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) if 1: - print(g.format_ctor(self, __file__), g.callers(4)) + print(g.format_ctor("PyModule", __file__)) super().__init__(pycore, node, resource) def _init_source(self, pycore, source_code, resource): @@ -424,14 +424,16 @@ def _ClassDef(self, node): pyclass = PyClass(self.pycore, node, self.owner_object) self.names[node.name] = pynamesdef.DefinedName(pyclass) if 1: - print(g.align("_ScopeVisitor", "_ClassDef"), node.name) + print(g.format("def _ClassDef", "_ScopeVisitor", "_ClassDef"), node.name) self.defineds.append(pyclass) def _FunctionDef(self, node): pyfunction = PyFunction(self.pycore, node, self.owner_object) if 1: - print(g.align("_ScopeVisitor", "_FunctionDef"), node.name) + print( + g.format("def _FunctionDef", "_ScopeVisitor", "_FunctionDef"), node.name + ) for decorator in pyfunction.decorators: if isinstance(decorator, ast.Name) and decorator.id == "property": diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index 2deac21d0..b94c316b0 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -72,20 +72,21 @@ def callers_list(n: int = 4) -> List[str]: def align(s1: str, s2) -> str: - return f"{' ':10} {s1:>16}.{s2:<15}" + return f"{' ':15} {s1:>16}.{s2:<15}" def format(caller_name: str, module: str, function: str = "") -> str: """Format caller_name, module and optional function, aligned for traces.""" module_s = module.replace("rope.base.", "") - return f"{caller_name:>10} {module_s:>16}.{function:<15}" + return f"{caller_name:>15} {module_s:>16}.{function:<15}" -def format_ctor(self: Any, file_name: str) -> str: - class_s = self.__class__.__name__ - # file_name_s = file_name.replace("rope.base.", "") +def format_ctor(class_name: str, file_name: str) -> str: + """Format a ctor, aligned for traces.""" + # Careful: use an explicit class name. + # self.__class__.__name__ can yield unexpected/confusing results. file_name_s = short_file_name(file_name) - return f"{'__init__':>10} {file_name_s:>16}.{class_s:<15}" + return f"{'__init__':>15} {file_name_s:>16}.{class_name:<15}" def plural(obj: Any) -> str: From 7f6b993797e2304bd3c0ff34f53e15dd6f6be5e6 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Wed, 8 Feb 2023 20:27:09 -0600 Subject: [PATCH 68/99] Improve tracing --- rope/base/ast.py | 2 +- rope/base/project.py | 7 ++++ rope/base/pynames.py | 6 +-- rope/base/pyobjectsdef.py | 4 +- ropetest/objectinfertest.py | 79 ++++++++++++------------------------- 5 files changed, 39 insertions(+), 59 deletions(-) diff --git a/rope/base/ast.py b/rope/base/ast.py index b4d3c0510..431384457 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -67,7 +67,7 @@ def visit(self, node): """Modified from ast.NodeVisitor to match rope's existing Visitor implementation""" method = "_" + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) - if 1: + if 0: module, name = visitor.__module__, visitor.__name__ if name != "generic_visit": print(g.format("visit", module, name)) diff --git a/rope/base/project.py b/rope/base/project.py index 81e78d2d1..91503562c 100644 --- a/rope/base/project.py +++ b/rope/base/project.py @@ -13,6 +13,8 @@ from rope.base.prefs import Prefs, get_config from rope.base.resources import File, Folder, _ResourceMatcher +from rope.base.utils import tracing_utils as g ### + try: import cPickle as pickle except ImportError: @@ -225,12 +227,17 @@ def __init__( self._init_source_folders() def __repr__(self): + # Changing this will cause a unit test to fail. return '<{}.{} "{}">'.format( self.__class__.__module__, self.__class__.__name__, self.address, ) + def description(self): + file_name = g.short_file_name(self.address) + return f"{self.__class__.__module__}.{self.__class__.__name__}:{file_name}" + @utils.deprecated("Delete once deprecated functions are gone") def _init_source_folders(self): for path in self.prefs.get("source_folders", []): diff --git a/rope/base/pynames.py b/rope/base/pynames.py index b0c0c2890..fdac877cc 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -11,7 +11,7 @@ from rope.base import pyobjectsdef from rope.base.pyobjects import PyObject -from rope.base.utils import tracing_utils as g +from rope.base.utils import tracing_utils as g ### assert g @@ -22,8 +22,7 @@ class PyName: if 1: # Temp ctor. def __init__(self): - g.trace("*****") ### Not called in basic test. - print(g.format_ctor("PyName", __file__)) + print(g.format_ctor("***PyName**", __file__)) def get_object(self) -> Optional[PyObject]: """Return the `PyObject` object referenced by this `PyName`""" @@ -39,6 +38,7 @@ def __init__(self, pyobject): self.pyobject = pyobject if 1: print(g.format_ctor("DefinedName", __file__), repr(pyobject)) + # print(self.__class__.__qualname__) def get_object(self): return self.pyobject diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 49dcd6f61..7387ef67f 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -423,14 +423,14 @@ def get_module(self): def _ClassDef(self, node): pyclass = PyClass(self.pycore, node, self.owner_object) self.names[node.name] = pynamesdef.DefinedName(pyclass) - if 1: + if 0: print(g.format("def _ClassDef", "_ScopeVisitor", "_ClassDef"), node.name) self.defineds.append(pyclass) def _FunctionDef(self, node): pyfunction = PyFunction(self.pycore, node, self.owner_object) - if 1: + if 0: print( g.format("def _FunctionDef", "_ScopeVisitor", "_FunctionDef"), node.name ) diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index c7e94aa4f..e96f48c2d 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -29,69 +29,42 @@ class Sample(object): a_var = Sample() """) - print('') - print('') - print('after: setUp') - print('before: get_string_scope\n') + # setUp creates self.project. + print('\n') + print('after: setUp\n') + print('self.project:', self.project.description()) - # 1. setUp creates self.project. - - # setUp instantiates self.project to a Project instance. - # self.project = testutils.sample_project() - - # 2. get_string_scope sets self.scope to the scope of the test string. - - # Sets self.scope to pyobjectsdef.PyModule(project.pycore, code, ...) - # (code is the test string, defined above.) - - # ??? Instantiating the pyobjectsdef.PyModule does all the work ??? - - # PyDefinedObject.__init__ calls: - - # self.concluded_attributes = self.get_module()._get_concluded_data() - # self.attributes = self.get_module()._get_concluded_data() - - # But all attributes are empty for this test. + print('\ndo: scope = libutils.get_string_scope(...)\n') scope = libutils.get_string_scope(self.project, code) - print('') - print('after: get_string_scope') - print('before: sample_class = scope["Sample"].get_object()\n') - - # scope is a GlobalScope. It might be any subclass of Scope. - # scope.pyobject is a pyobjectsdef.PyModule. + print('\nscope:', scope) + print('scope.pyobject', scope.pyobject) - # if trace: g.trace('*** scope.pyobject', scope.pyobject) + print('\ndo: sample_scope = scope["Sample"]\n') - # *** Calling scope["Sample"] (via _ScopeVisitor._ClassDef) - # instantiates pyobjects.PyClass *and* pyobjectsdef.PyClass. - # (Because pyobjectsDef.PyClass is a subclass of pyobjects.PyClass.) - # scope["Sample"] is a pynamesdef.DefinedName. - - sample_class = scope["Sample"].get_object() - - print('') - print('after: sample_class = scope["Sample"].get_object()') - print('before: a_var = scope["a_var"].get_object()\n') - - # sample_class is a pyobjectsdef.PyClass ("::Sample" at ...) - # scope["Sample"] is a DefinedName. - # scope["Sample"].pyobject is a pyobjectsdef.PyClass. - - a_var = scope["a_var"].get_object() + sample_scope = scope["Sample"] + + print('\nsample_scope:', sample_scope) - print('') - print('after: a_var = scope["a_var"].get_object()\n') + print('\ndo: sample_scope.get_object()') - # a_var is a pyobjects.PyObject - # a_var.get_type() is a pyobjectsdef.PyClass ("::Sample" at ...) + sample_class = sample_scope.get_object() - # scope["a_var"] is an pynamesdef.AssignedName. - # scope["a_var"].pyobject is a pynames._Inferred. - # scope["a_var"].get_object() is a pyobjects.PyObject. + print('\nsample_class:', sample_class) + + print('\ndo: na_var_scope = scope["a_var"]\n') + + a_var_scope = scope["a_var"] + + print('a_var_scope', a_var_scope) + + print('\ndo: a_var = a_var_scope.get_object()\n') + + a_var = a_var_scope.get_object() - print(f"sample_class: {sample_class}") + print(' a_var:', a_var) + print('a_var.get_type():', a_var.get_type()) self.assertEqual(sample_class, a_var.get_type()) def test_simple_type_inferencing_classes_defined_in_holding_scope(self): From 934361afcf470b4e447c2c5bbadd6eab580e9a03 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 9 Feb 2023 07:26:36 -0600 Subject: [PATCH 69/99] Add/improve traces --- rope/base/ast.py | 2 +- rope/base/project.py | 10 ++++++---- rope/base/pycore.py | 8 ++++++++ rope/base/pynames.py | 5 ++--- rope/base/pynamesdef.py | 8 ++++++++ rope/base/pyobjects.py | 23 ++++++++++++++++------- rope/base/pyobjectsdef.py | 16 ++++++++++++++-- rope/base/utils/tracing_utils.py | 2 +- ropetest/objectinfertest.py | 7 ++++++- 9 files changed, 62 insertions(+), 19 deletions(-) diff --git a/rope/base/ast.py b/rope/base/ast.py index 431384457..fe5da7586 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -67,7 +67,7 @@ def visit(self, node): """Modified from ast.NodeVisitor to match rope's existing Visitor implementation""" method = "_" + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) - if 0: + if 0: # trace module, name = visitor.__module__, visitor.__name__ if name != "generic_visit": print(g.format("visit", module, name)) diff --git a/rope/base/project.py b/rope/base/project.py index 91503562c..cfd5dd176 100644 --- a/rope/base/project.py +++ b/rope/base/project.py @@ -226,7 +226,7 @@ def __init__( self.prefs.add("ignored_resources", ropefolder) self._init_source_folders() - def __repr__(self): + def __repr__(self) -> str: # Changing this will cause a unit test to fail. return '<{}.{} "{}">'.format( self.__class__.__module__, @@ -234,9 +234,11 @@ def __repr__(self): self.address, ) - def description(self): - file_name = g.short_file_name(self.address) - return f"{self.__class__.__module__}.{self.__class__.__name__}:{file_name}" + def description(self) -> str: + if 1: # trace + file_name = g.short_file_name(self.address) + return f"{self.__class__.__module__}.{self.__class__.__name__}:{file_name}" + return "" @utils.deprecated("Delete once deprecated functions are gone") def _init_source_folders(self): diff --git a/rope/base/pycore.py b/rope/base/pycore.py index c1ad7e426..264e0c98f 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -13,6 +13,8 @@ import rope.base.resources from rope.base import builtins, exceptions, pyobjectsdef, stdmods, taskhandle, utils +from rope.base.utils import tracing_utils as g + if TYPE_CHECKING: from rope.base.pyscopes import Scope from rope.base.resources import Resource @@ -28,6 +30,12 @@ def __init__(self, project): self.object_info = rope.base.oi.objectinfo.ObjectInfoManager(project) self._init_python_files() self._init_automatic_soa() + if 1: # trace + # This will be the first enabled print statement, + # if there is no trace in any setUp method. + print("\n") + if 1: # trace + print(g.format_ctor("PyCore", __file__)) def _init_python_files(self): self.python_matcher = None diff --git a/rope/base/pynames.py b/rope/base/pynames.py index fdac877cc..117ba247c 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -19,7 +19,7 @@ class PyName: """References to `PyObject` inside python programs""" - if 1: # Temp ctor. + if 1: # trace (temp ctor) def __init__(self): print(g.format_ctor("***PyName**", __file__)) @@ -36,9 +36,8 @@ def get_definition_location(self) -> Optional[Tuple[Any, int]]: class DefinedName(PyName): def __init__(self, pyobject): self.pyobject = pyobject - if 1: + if 1: # trace print(g.format_ctor("DefinedName", __file__), repr(pyobject)) - # print(self.__class__.__qualname__) def get_object(self): return self.pyobject diff --git a/rope/base/pynamesdef.py b/rope/base/pynamesdef.py index 3aa8e7fc3..3b268836f 100644 --- a/rope/base/pynamesdef.py +++ b/rope/base/pynamesdef.py @@ -4,6 +4,10 @@ import rope.base.pyobjects from rope.base import pynames, utils +from rope.base.utils import tracing_utils as g + +assert g + class DefinedName(pynames.DefinedName): pass @@ -18,6 +22,8 @@ def __init__(self, lineno=None, module=None, pyobject=None): self._get_inferred, pynames._get_concluded_data(module) ) self.pyobject.set(pyobject) + if 1: # trace + print(g.format_ctor("pynamesdef.AssignedName", __file__), repr(pyobject)) @utils.prevent_recursion(lambda: None) def _get_inferred(self): @@ -47,6 +53,8 @@ class ParameterName(pynames.ParameterName): def __init__(self, pyfunction, index): self.pyfunction = pyfunction self.index = index + if 1: # trace + print(g.format_ctor("ParameterName", __file__), repr(pyfunction)) def get_object(self): result = self.pyfunction.get_parameter(self.index) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 33ddd8387..c1fcd2ec4 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -123,6 +123,8 @@ def get_unknown(): class AbstractClass(PyObject): def __init__(self): + if 0: # trace This trace disables all other traces!!! + print(g.format_ctor("AbstractClass", __file__), g.callers(1)) super().__init__(get_base_type("Type")) def get_name(self): @@ -175,7 +177,7 @@ def __init__(self, pycore, ast_node, parent): self.concluded_attributes = self.get_module()._get_concluded_data() self.attributes = self.get_module()._get_concluded_data() self.defineds = None - if 1: + if 1: # trace # trace print(g.format_ctor("DefinedObject", __file__), ast_node) def __repr__(self): @@ -282,9 +284,21 @@ class PyClass(PyDefinedObject, AbstractClass): class _ConcludedData: def __init__(self): self.data_ = None + if 1: # trace + import re + + pat = re.compile(r"_?[A-Z]") + callers_s = ",".join([z for z in g.callers_list(20) if re.match(pat, z)]) + print( + g.format_ctor("_ConcludedData", __file__), f"id: {id(self)}", callers_s + ) def set(self, data): self.data_ = data + if 0: # trace + tag = f"_ConcludedData.set: {id(self)}" + n = 2 if isinstance(data, (dict, list, set)) else 6 + print(f"{tag} {data.__class__.__name__:<14}", g.callers(n)) def get(self): return self.data_ @@ -297,11 +311,6 @@ def _invalidate(self): def __str__(self): return "pyobjects._ConcludedData<" + str(self.data) + ">" - ### - - def _ekr_dump(self): - g.print_obj(self.data, tag=f"***** pyobjects._ConcludedData: {id(self)}") - class _PyModule(PyDefinedObject, AbstractModule): def __init__(self, pycore, ast_node, resource): @@ -309,7 +318,7 @@ def __init__(self, pycore, ast_node, resource): self.concluded_data = [] AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) - if 1: + if 1: # trace # trace print(g.format_ctor("PyModule", __file__)) @property diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 7387ef67f..22a24429b 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -137,7 +137,7 @@ def __init__(self, pycore, ast_node, parent): rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent) self.parent = parent self._superclasses = self.get_module()._get_concluded_data() - if 1: + if 1: # trace print(g.format_ctor("PyClass", __file__), ast_node.name) def get_superclasses(self): @@ -188,7 +188,7 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.star_imports = [] self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) - if 1: + if 1: # trace print(g.format_ctor("PyModule", __file__)) super().__init__(pycore, node, resource) @@ -304,6 +304,8 @@ def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None self.type_hint = None + if 1: # trace + print(g.format_ctor("_AnnAssignVisitor", __file__)) def _AnnAssign(self, node): self.assigned_ast = node.value @@ -344,6 +346,8 @@ def _Slice(self, node): class _ExpressionVisitor(ast.RopeNodeVisitor): def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor + if 1: # trace + print(g.format_ctor("_ExpressionVisitor", __file__)) def _assigned(self, name, assignment=None): self.scope_visitor._assigned(name, assignment) @@ -372,6 +376,8 @@ class _AssignVisitor(ast.RopeNodeVisitor): def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None + if 1: # trace + print(g.format_ctor("_AssignVisitor", __file__)) def _Assign(self, node): self.assigned_ast = node.value @@ -413,6 +419,8 @@ def __init__(self, pycore, owner_object): self.owner_object = owner_object self.names = {} self.defineds = [] + if 1: # trace + print(g.format_ctor("_ScopeVisitor", __file__)) def get_module(self): if self.owner_object is not None: @@ -620,6 +628,8 @@ def __init__(self, pycore, owner_object): super().__init__(pycore, owner_object) self.returned_asts = [] self.generator = False + if 1: # trace + print(g.format_ctor("_FunctionVisitor", __file__)) def _Return(self, node): if node.value is not None: @@ -635,6 +645,8 @@ class _ClassInitVisitor(_AssignVisitor): def __init__(self, scope_visitor, self_name): super().__init__(scope_visitor) self.self_name = self_name + if 1: # trace + print(g.format_ctor("_ClassInitVisitor", __file__)) def _Attribute(self, node): if not isinstance(node.ctx, ast.Store): diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index b94c316b0..1ea3a3598 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -86,7 +86,7 @@ def format_ctor(class_name: str, file_name: str) -> str: # Careful: use an explicit class name. # self.__class__.__name__ can yield unexpected/confusing results. file_name_s = short_file_name(file_name) - return f"{'__init__':>15} {file_name_s:>16}.{class_name:<15}" + return f"{'__init__':>15} {file_name_s:>16}:{class_name:<15}" def plural(obj: Any) -> str: diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index e96f48c2d..bd4fde841 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -15,8 +15,12 @@ def setUp(self): Init self.project to a new Project instance for this test, with default prefs. self.project.fscommands manages temp files in a temp directory. """ + if 0: # trace: Do this before calling super().setUp() + print('\n') + print('ObjectInferTest.setUp\n') super().setUp() self.project = testutils.sample_project() + def tearDown(self): testutils.remove_project(self.project) @@ -30,7 +34,7 @@ class Sample(object): """) # setUp creates self.project. - print('\n') + print('') print('after: setUp\n') print('self.project:', self.project.description()) @@ -63,6 +67,7 @@ class Sample(object): a_var = a_var_scope.get_object() + print('') print(' a_var:', a_var) print('a_var.get_type():', a_var.get_type()) From 4dff16a8b762bc31c7a948947769d3459b690a50 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 9 Feb 2023 08:20:44 -0600 Subject: [PATCH 70/99] Improve traces, again --- rope/base/pyobjects.py | 20 ++++++++++++-------- rope/base/utils/tracing_utils.py | 14 +++++++++----- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index c1fcd2ec4..58c406e06 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -123,8 +123,8 @@ def get_unknown(): class AbstractClass(PyObject): def __init__(self): - if 0: # trace This trace disables all other traces!!! - print(g.format_ctor("AbstractClass", __file__), g.callers(1)) + if 0: # trace !!!This trace disables all other traces!!! + print(g.format_ctor("AbstractClass", __file__)) super().__init__(get_base_type("Type")) def get_name(self): @@ -285,19 +285,23 @@ class _ConcludedData: def __init__(self): self.data_ = None if 1: # trace - import re + ### + # import re + # pat = re.compile(r"_?[A-Z]") + # callers_s = ",".join([z for z in g.callers_list(20) if re.match(pat, z)]) + # print(g.format_ctor("_ConcludedData", __file__), f"id: {id(self)}", callers_s) - pat = re.compile(r"_?[A-Z]") - callers_s = ",".join([z for z in g.callers_list(20) if re.match(pat, z)]) print( - g.format_ctor("_ConcludedData", __file__), f"id: {id(self)}", callers_s + g.format_ctor("_ConcludedData", __file__), + f"id: {id(self)}", + g.callers(4), ) def set(self, data): self.data_ = data - if 0: # trace + if 1: # trace tag = f"_ConcludedData.set: {id(self)}" - n = 2 if isinstance(data, (dict, list, set)) else 6 + n = 2 if isinstance(data, (dict, list, set)) else 4 print(f"{tag} {data.__class__.__name__:<14}", g.callers(n)) def get(self): diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index 1ea3a3598..30ee99690 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -16,12 +16,16 @@ def _caller_name(n: int) -> str: # Get the function name from the call stack. frame = sys._getframe(n) # The stack frame, n levels up. code = frame.f_code # The code object - locals_ = frame.f_locals # The local namespace. name = code.co_name - obj = locals_.get("self") - if obj and name == "__init__": - return f"{obj.__class__.__name__}.{name}" - return name + file_name = short_file_name(code.co_filename)[:-3] + # if 0: + # locals_ = frame.f_locals # The local namespace. + # file_name = short_file_name(code.co_filename) + # obj = locals_.get("self") + # trace(repr(name), repr(obj), repr(file_name)) ### + # if obj and name == "__init__": + # return f"**{file_name}:{obj.__class__.__name__}.{name}" + return f"{file_name}:{name}" except ValueError: # The stack is not deep enough OR # sys._getframe does not exist on this platform. From c1ea12b86207bf9dcb08fdbbe1978f999bda84c3 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 9 Feb 2023 09:29:36 -0600 Subject: [PATCH 71/99] Revise again --- rope/base/builtins.py | 6 ++++++ rope/base/pyobjects.py | 9 +++++++++ rope/base/utils/tracing_utils.py | 11 ++--------- ropetest/objectinfertest.py | 12 +++++++++--- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/rope/base/builtins.py b/rope/base/builtins.py index 151c64742..12224be19 100644 --- a/rope/base/builtins.py +++ b/rope/base/builtins.py @@ -5,6 +5,10 @@ import rope.base.evaluate from rope.base import arguments, ast, pynames, pyobjects, utils +from rope.base.utils import tracing_utils as g + +assert g + class BuiltinModule(pyobjects.AbstractModule): def __init__(self, name, pycore=None, initial={}): @@ -12,6 +16,8 @@ def __init__(self, name, pycore=None, initial={}): self.name = name self.pycore = pycore self.initial = initial + if 1: # trace + print(g.format_ctor("pyobjects.PyObject", __file__), name) parent = None diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 58c406e06..5edebcaa0 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -11,6 +11,15 @@ class PyObject: def __init__(self, type_): if type_ is None: type_ = self + + if 1: # trace + if not hasattr(self, "type") or type_ != self.type: + if "builtins" not in g.callers(): + print( + g.format_ctor("PyObject", __file__), + f"id: {id(self)}", + g.callers(2), + ) self.type = type_ def get_attributes(self): diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index 30ee99690..49bb33404 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -18,13 +18,6 @@ def _caller_name(n: int) -> str: code = frame.f_code # The code object name = code.co_name file_name = short_file_name(code.co_filename)[:-3] - # if 0: - # locals_ = frame.f_locals # The local namespace. - # file_name = short_file_name(code.co_filename) - # obj = locals_.get("self") - # trace(repr(name), repr(obj), repr(file_name)) ### - # if obj and name == "__init__": - # return f"**{file_name}:{obj.__class__.__name__}.{name}" return f"{file_name}:{name}" except ValueError: # The stack is not deep enough OR @@ -46,7 +39,7 @@ def callers(n: int = 4) -> str: """ # Be careful to call _caller_name with smaller values of i first: # sys._getframe throws ValueError if there are less than i entries. - i, result = 3, [] + i, result = 4, [] while 1: s = _caller_name(n=i) if s: @@ -54,7 +47,7 @@ def callers(n: int = 4) -> str: if not s or len(result) >= n: break i += 1 - return ",".join(reversed(result)) + return ", ".join(reversed(result)) def callers_list(n: int = 4) -> List[str]: diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index bd4fde841..99f509b09 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -42,8 +42,9 @@ class Sample(object): scope = libutils.get_string_scope(self.project, code) - print('\nscope:', scope) - print('scope.pyobject', scope.pyobject) + print('') + print(' scope:', scope) + print('scope.pyobject:', scope.pyobject) print('\ndo: sample_scope = scope["Sample"]\n') @@ -61,7 +62,7 @@ class Sample(object): a_var_scope = scope["a_var"] - print('a_var_scope', a_var_scope) + print('a_var_scope:', a_var_scope) print('\ndo: a_var = a_var_scope.get_object()\n') @@ -70,8 +71,13 @@ class Sample(object): print('') print(' a_var:', a_var) print('a_var.get_type():', a_var.get_type()) + + print('\ndo: self.assertEqual(sample_class, a_var.get_type())') self.assertEqual(sample_class, a_var.get_type()) + + print('') + print('sample_class:', sample_class) def test_simple_type_inferencing_classes_defined_in_holding_scope(self): code = dedent("""\ class Sample(object): From cafc16855ba88c002319ae780c9215dd55978bb7 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 9 Feb 2023 14:44:00 -0600 Subject: [PATCH 72/99] More traces --- rope/base/pynames.py | 4 +++- rope/base/pynamesdef.py | 5 ++++- rope/base/pyobjects.py | 3 ++- rope/base/pyobjectsdef.py | 21 ++++++++++++++++++- rope/base/pyscopes.py | 36 ++++++++++++++++++++++++++++++++ rope/base/utils/tracing_utils.py | 3 ++- 6 files changed, 67 insertions(+), 5 deletions(-) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 117ba247c..422e9fd03 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -19,6 +19,8 @@ class PyName: """References to `PyObject` inside python programs""" + ### Holds analysis of assignments statements. + if 1: # trace (temp ctor) def __init__(self): @@ -37,7 +39,7 @@ class DefinedName(PyName): def __init__(self, pyobject): self.pyobject = pyobject if 1: # trace - print(g.format_ctor("DefinedName", __file__), repr(pyobject)) + print(g.format_ctor("DefinedName", __file__), f"pyobject: {pyobject!r}") def get_object(self): return self.pyobject diff --git a/rope/base/pynamesdef.py b/rope/base/pynamesdef.py index 3b268836f..6bda46f22 100644 --- a/rope/base/pynamesdef.py +++ b/rope/base/pynamesdef.py @@ -23,7 +23,10 @@ def __init__(self, lineno=None, module=None, pyobject=None): ) self.pyobject.set(pyobject) if 1: # trace - print(g.format_ctor("pynamesdef.AssignedName", __file__), repr(pyobject)) + print( + g.format_ctor("pynamesdef.AssignedName", __file__), + f"pyobject: {pyobject!r}", + ) @utils.prevent_recursion(lambda: None) def _get_inferred(self): diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 5edebcaa0..be4d4ddc7 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -308,10 +308,11 @@ def __init__(self): def set(self, data): self.data_ = data - if 1: # trace + if 0: # trace: now done in the get_names methods of Scopes. tag = f"_ConcludedData.set: {id(self)}" n = 2 if isinstance(data, (dict, list, set)) else 4 print(f"{tag} {data.__class__.__name__:<14}", g.callers(n)) + print(g.to_string(data)) def get(self): return self.data_ diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 22a24429b..8cff5d98a 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -138,7 +138,20 @@ def __init__(self, pycore, ast_node, parent): self.parent = parent self._superclasses = self.get_module()._get_concluded_data() if 1: # trace - print(g.format_ctor("PyClass", __file__), ast_node.name) + print(g.format_ctor("PyClass", __file__), "node.name:", ast_node.name) + + if 0: # trace + # Overried po.PyDefinedObject.__repr__ + + # return '<{}.{} "{}" at {}>'.format( + # self.__class__.__module__, + # self.__class__.__name__, + # self.absolute_name, + # hex(id(self)), + # ) + + def __repr__(self) -> str: + return f"pyobjectsdef.PyClass: {self.absolute_name}" def get_superclasses(self): if self._superclasses.get() is None: @@ -695,4 +708,10 @@ def get_names(self): for name in imported: if not name.startswith("_"): result[name] = pynamesdef.ImportedName(self.imported_module, name) + if 1: # trace + data = result + tag = "StarImport.get_names" + # n = 2 if isinstance(data, (dict, list, set)) else 4 + print(f"{tag:>20} {data.__class__.__name__:<14}", g.callers(4)) + print(g.to_string(data)) return result diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index 322209974..5ce35bb38 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -15,6 +15,17 @@ def __init__(self, pycore, pyobject, parent_scope): def get_names(self): """Return the names defined or imported in this scope""" + if 1: # trace + data = self.pyobject.get_attributes() + print("Scope.get_names", g.callers(6)) + if 0: ### Fails in general. + for z in data: + print( + f"{z:>10} {data[z].__class__.__name__:<12} pyobject: {data[z].pyobject}" + ) + print("") + else: + print(f"\n{g.to_string(data)}\n") return self.pyobject.get_attributes() def get_defined_names(self): @@ -151,6 +162,12 @@ def get_names(self): result = dict(self.builtin_names) result.update(super().get_names()) self.names.set(result) + if 0: # trace + data = self.names.get() + tag = "GlobalScope.get_names" + # n = 2 if isinstance(data, (dict, list, set)) else 4 + print(f"{tag:>20} {data.__class__.__name__:<14}", g.callers(4)) + print(g.to_string(data)) return self.names.get() def get_inner_scope_for_line(self, lineno, indents=None): @@ -183,6 +200,13 @@ def _get_names(self): return self.names def get_names(self): + if 1: # trace + data = self._get_names() + tag = "ComprehensionScope.get_names" + # n = 2 if isinstance(data, (dict, list, set)) else 4 + print(f"{tag:>20} {data.__class__.__name__:<14}", g.callers(4)) + print(g.to_string(data, indent=4)) + return self._get_names() def _visit_comprehension(self): @@ -239,6 +263,12 @@ def _is_generator(self): return self.is_generator def get_names(self): + if 1: # trace + data = self._get_names() + tag = "FunctionScope.get_names" + # n = 2 if isinstance(data, (dict, list, set)) else 4 + print(f"{tag:>20} {data.__class__.__name__:<14}", g.callers(4)) + print(g.to_string(data)) return self._get_names() def _create_scopes(self): @@ -362,6 +392,12 @@ def __init__(self, pycore, parent_scope, names): self.names = names def get_names(self): + if 1: # trace + data = self.names + tag = "TemporaryScope.get_names" + # n = 2 if isinstance(data, (dict, list, set)) else 4 + print(f"{tag:>20} {data.__class__.__name__:<14}", g.callers(4)) + print(g.to_string(data)) return self.names def get_defined_names(self): diff --git a/rope/base/utils/tracing_utils.py b/rope/base/utils/tracing_utils.py index 49bb33404..8048db271 100644 --- a/rope/base/utils/tracing_utils.py +++ b/rope/base/utils/tracing_utils.py @@ -122,7 +122,8 @@ def to_string(obj: Any, indent: int = 0, tag: str = None, width: int = 120) -> s if not isinstance(obj, str): result = pprint.pformat(obj, indent=indent, width=width) elif "\n" not in obj: - result = repr(obj) + # result = repr(obj) + result = f"{' '*indent} {obj!r}" else: # Return the enumerated lines of the string. lines = "".join([f" {i:4}: {z!r}\n" for i, z in enumerate(split_lines(obj))]) From d44638e9782fdb35e34065dd0bcbf7574686b871 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Thu, 9 Feb 2023 17:43:57 -0600 Subject: [PATCH 73/99] Zero in on important traces/methods --- rope/base/builtins.py | 2 +- rope/base/pycore.py | 4 ++-- rope/base/pyobjects.py | 12 ++++++---- rope/base/pyobjectsdef.py | 48 +++++++++++++++++++++++++++------------ rope/base/pyscopes.py | 7 +++--- 5 files changed, 49 insertions(+), 24 deletions(-) diff --git a/rope/base/builtins.py b/rope/base/builtins.py index 12224be19..721c8a627 100644 --- a/rope/base/builtins.py +++ b/rope/base/builtins.py @@ -16,7 +16,7 @@ def __init__(self, name, pycore=None, initial={}): self.name = name self.pycore = pycore self.initial = initial - if 1: # trace + if 0: # trace print(g.format_ctor("pyobjects.PyObject", __file__), name) parent = None diff --git a/rope/base/pycore.py b/rope/base/pycore.py index 264e0c98f..828e8160c 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -30,11 +30,11 @@ def __init__(self, project): self.object_info = rope.base.oi.objectinfo.ObjectInfoManager(project) self._init_python_files() self._init_automatic_soa() - if 1: # trace + if 0: # trace # This will be the first enabled print statement, # if there is no trace in any setUp method. print("\n") - if 1: # trace + if 0: # trace print(g.format_ctor("PyCore", __file__)) def _init_python_files(self): diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index be4d4ddc7..302a74c80 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -12,7 +12,7 @@ def __init__(self, type_): if type_ is None: type_ = self - if 1: # trace + if 0: # trace if not hasattr(self, "type") or type_ != self.type: if "builtins" not in g.callers(): print( @@ -187,7 +187,11 @@ def __init__(self, pycore, ast_node, parent): self.attributes = self.get_module()._get_concluded_data() self.defineds = None if 1: # trace # trace - print(g.format_ctor("DefinedObject", __file__), ast_node) + # print('') + print( + g.format_ctor("PyDefinedObject", __file__), + f"ast_node: {ast_node.__class__.__name__}", + ) def __repr__(self): return '<{}.{} "{}" at {}>'.format( @@ -293,7 +297,7 @@ class PyClass(PyDefinedObject, AbstractClass): class _ConcludedData: def __init__(self): self.data_ = None - if 1: # trace + if 0: # trace ### # import re # pat = re.compile(r"_?[A-Z]") @@ -332,7 +336,7 @@ def __init__(self, pycore, ast_node, resource): self.concluded_data = [] AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) - if 1: # trace # trace + if 0: # trace # trace print(g.format_ctor("PyModule", __file__)) @property diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 8cff5d98a..e96b15548 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -201,7 +201,7 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.star_imports = [] self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) - if 1: # trace + if 0: # trace print(g.format_ctor("PyModule", __file__)) super().__init__(pycore, node, resource) @@ -317,7 +317,7 @@ def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None self.type_hint = None - if 1: # trace + if 0: # trace print(g.format_ctor("_AnnAssignVisitor", __file__)) def _AnnAssign(self, node): @@ -359,7 +359,7 @@ def _Slice(self, node): class _ExpressionVisitor(ast.RopeNodeVisitor): def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor - if 1: # trace + if 0: # trace print(g.format_ctor("_ExpressionVisitor", __file__)) def _assigned(self, name, assignment=None): @@ -389,9 +389,11 @@ class _AssignVisitor(ast.RopeNodeVisitor): def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None - if 1: # trace + if 0: # trace print(g.format_ctor("_AssignVisitor", __file__)) + # Assign(expr* targets, expr value, string? type_comment) + def _Assign(self, node): self.assigned_ast = node.value for child_node in node.targets: @@ -401,12 +403,16 @@ def _Assign(self, node): def _assigned(self, name, assignment=None): self.scope_visitor._assigned(name, assignment) + # Name(identifier id, expr_context ctx) + def _Name(self, node): assignment = None if self.assigned_ast is not None: assignment = pynamesdef.AssignmentValue(self.assigned_ast) self._assigned(node.id, assignment) + # Tuple(expr* elts, expr_context ctx) + def _Tuple(self, node): names = nameanalyze.get_name_levels(node) for name, levels in names: @@ -432,7 +438,7 @@ def __init__(self, pycore, owner_object): self.owner_object = owner_object self.names = {} self.defineds = [] - if 1: # trace + if 0: # trace print(g.format_ctor("_ScopeVisitor", __file__)) def get_module(self): @@ -444,18 +450,17 @@ def get_module(self): def _ClassDef(self, node): pyclass = PyClass(self.pycore, node, self.owner_object) self.names[node.name] = pynamesdef.DefinedName(pyclass) - if 0: - print(g.format("def _ClassDef", "_ScopeVisitor", "_ClassDef"), node.name) + if 1: + print("") + g.trace( + f"ScopeVisitor._ClassDef: NEW DefinedName: {node.name}: " + f"{self.names[node.name]}\n" + ) self.defineds.append(pyclass) def _FunctionDef(self, node): pyfunction = PyFunction(self.pycore, node, self.owner_object) - if 0: - print( - g.format("def _FunctionDef", "_ScopeVisitor", "_FunctionDef"), node.name - ) - for decorator in pyfunction.decorators: if isinstance(decorator, ast.Name) and decorator.id == "property": if isinstance(self, _ClassVisitor): @@ -477,6 +482,13 @@ def _eval(type_=type_, arg=arg): break else: self.names[node.name] = pynamesdef.DefinedName(pyfunction) + + if 1: + print("") + g.trace( + f"ScopeVisitor._FunctionDef: NEW DefinedName: {node.name}: " + f"{self.names[node.name]}\n" + ) self.defineds.append(pyfunction) def _AsyncFunctionDef(self, node): @@ -503,9 +515,17 @@ def _assigned(self, name, assignment): pyname = self.names.get(name, None) if pyname is None: pyname = pynamesdef.AssignedName(module=self.get_module()) + if 1: # trace + print("") + g.trace(f"ScopeVisitor._assigned: NEW pyname: {pyname}") if isinstance(pyname, pynamesdef.AssignedName): if assignment is not None: pyname.assignments.append(assignment) + if 1: # trace + g.trace( + f"ScopeVisitor._assigned: NEW append to assignments: {assignment}" + ) + # print("") self.names[name] = pyname def _update_evaluated( @@ -641,7 +661,7 @@ def __init__(self, pycore, owner_object): super().__init__(pycore, owner_object) self.returned_asts = [] self.generator = False - if 1: # trace + if 0: # trace print(g.format_ctor("_FunctionVisitor", __file__)) def _Return(self, node): @@ -658,7 +678,7 @@ class _ClassInitVisitor(_AssignVisitor): def __init__(self, scope_visitor, self_name): super().__init__(scope_visitor) self.self_name = self_name - if 1: # trace + if 0: # trace print(g.format_ctor("_ClassInitVisitor", __file__)) def _Attribute(self, node): diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index 5ce35bb38..a11d37957 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -17,14 +17,15 @@ def get_names(self): """Return the names defined or imported in this scope""" if 1: # trace data = self.pyobject.get_attributes() - print("Scope.get_names", g.callers(6)) - if 0: ### Fails in general. + # print("Scope.get_names", g.callers(6)) + try: + # Fails in general... for z in data: print( f"{z:>10} {data[z].__class__.__name__:<12} pyobject: {data[z].pyobject}" ) print("") - else: + except Exception: print(f"\n{g.to_string(data)}\n") return self.pyobject.get_attributes() From c89c58e7984c5930b2d8e1cda761af2682a2c896 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 07:50:36 -0600 Subject: [PATCH 74/99] Add/suppress annotations --- rope/base/arguments.py | 23 ++++++++++++++++++++--- rope/base/ast.py | 2 +- rope/base/builtins.py | 2 +- rope/base/fscommands.py | 1 + rope/base/oi/doa.py | 1 + rope/base/oi/runmod.py | 2 +- rope/base/project.py | 1 + rope/base/versioning.py | 1 + rope/refactor/move.py | 1 + 9 files changed, 28 insertions(+), 6 deletions(-) diff --git a/rope/base/arguments.py b/rope/base/arguments.py index 12a626816..39684ace0 100644 --- a/rope/base/arguments.py +++ b/rope/base/arguments.py @@ -1,6 +1,18 @@ +from __future__ import annotations +from typing import Any, Union, TYPE_CHECKING import rope.base.evaluate from rope.base import ast +if TYPE_CHECKING: + from rope.base.pyobjects import PyFunction + from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction + from rope.base.pyscopes import Scope + + PyFunc = Union[PyFunction, DefinedPyFunction] +else: + PyFunc = Any + Scope = Any + class Arguments: """A class for evaluating parameters passed to a function @@ -41,10 +53,15 @@ def _evaluate(self, ast_node): return rope.base.evaluate.eval_node(self.scope, ast_node) -def create_arguments(primary, pyfunction, call_node, scope): +# Call(expr func, expr* args, keyword* keywords) + + +def create_arguments( + primary, pyfunction: PyFunc, call_node: ast.Call, scope: Scope +) -> Arguments: """A factory for creating `Arguments`""" args = list(call_node.args) - args.extend(call_node.keywords) + args.extend(call_node.keywords) # type:ignore called = call_node.func # XXX: Handle constructors if _is_method_call(primary, pyfunction) and isinstance(called, ast.Attribute): @@ -94,7 +111,7 @@ def get_instance_pyname(self): return self.pyname -def _is_method_call(primary, pyfunction): +def _is_method_call(primary: Any, pyfunction: PyFunc) -> bool: if primary is None: return False pyobject = primary.get_object() diff --git a/rope/base/ast.py b/rope/base/ast.py index fe5da7586..15c675b8f 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -9,7 +9,7 @@ assert g try: - from ast import _const_node_type_names + from ast import _const_node_type_names # type:ignore except ImportError: # backported from stdlib `ast` assert sys.version_info < (3, 8) diff --git a/rope/base/builtins.py b/rope/base/builtins.py index 721c8a627..6bffbeaf3 100644 --- a/rope/base/builtins.py +++ b/rope/base/builtins.py @@ -17,7 +17,7 @@ def __init__(self, name, pycore=None, initial={}): self.pycore = pycore self.initial = initial if 0: # trace - print(g.format_ctor("pyobjects.PyObject", __file__), name) + print(g.format_ctor("builtins.BuiltinModule", __file__), name) parent = None diff --git a/rope/base/fscommands.py b/rope/base/fscommands.py index b7960594a..7e71cf00f 100644 --- a/rope/base/fscommands.py +++ b/rope/base/fscommands.py @@ -1,3 +1,4 @@ +# type:ignore """Project file system commands. This modules implements file system operations used by rope. Different diff --git a/rope/base/oi/doa.py b/rope/base/oi/doa.py index 57b68ce5c..ab5f9505f 100644 --- a/rope/base/oi/doa.py +++ b/rope/base/oi/doa.py @@ -1,3 +1,4 @@ +# type:ignore import base64 import contextlib import hashlib diff --git a/rope/base/oi/runmod.py b/rope/base/oi/runmod.py index 4679ebb45..3bb7c1394 100644 --- a/rope/base/oi/runmod.py +++ b/rope/base/oi/runmod.py @@ -4,7 +4,7 @@ def __rope_start_everything(): import sys try: - import cPickle as pickle + import cPickle as pickle # type:ignore except ImportError: import pickle import base64 diff --git a/rope/base/project.py b/rope/base/project.py index cfd5dd176..e7372349d 100644 --- a/rope/base/project.py +++ b/rope/base/project.py @@ -1,3 +1,4 @@ +# type:ignore import contextlib import json import os diff --git a/rope/base/versioning.py b/rope/base/versioning.py index 985255e47..c27b667e2 100644 --- a/rope/base/versioning.py +++ b/rope/base/versioning.py @@ -1,3 +1,4 @@ +# type:ignore import hashlib import importlib.util import json diff --git a/rope/refactor/move.py b/rope/refactor/move.py index 2081dee02..69a4843f4 100644 --- a/rope/refactor/move.py +++ b/rope/refactor/move.py @@ -1,3 +1,4 @@ +# type:ignore """A module containing classes for move refactoring `create_move()` is a factory for creating move refactoring objects From 3f7ae15d3aab5cd33595dcfc3765548227e631b0 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 08:22:13 -0600 Subject: [PATCH 75/99] Fix/suppress all remaining mypy complaints --- rope/base/arguments.py | 1 + rope/base/change.py | 4 ++-- rope/base/oi/soa.py | 16 ++++++++++++++-- rope/base/oi/soi.py | 19 ++++++++++++++++--- rope/base/oi/type_hinting/utils.py | 1 + rope/base/pynamesdef.py | 12 +++++++++++- rope/base/pyobjects.py | 3 ++- rope/base/pyobjectsdef.py | 6 +++++- rope/contrib/autoimport/sqlite.py | 1 + rope/contrib/autoimport/utils.py | 2 +- rope/contrib/generate.py | 2 +- rope/refactor/importutils/module_imports.py | 2 +- 12 files changed, 56 insertions(+), 13 deletions(-) diff --git a/rope/base/arguments.py b/rope/base/arguments.py index 39684ace0..fe217b05c 100644 --- a/rope/base/arguments.py +++ b/rope/base/arguments.py @@ -12,6 +12,7 @@ else: PyFunc = Any Scope = Any +Node = ast.AST class Arguments: diff --git a/rope/base/change.py b/rope/base/change.py index a6871f867..38173fc46 100644 --- a/rope/base/change.py +++ b/rope/base/change.py @@ -6,7 +6,7 @@ import rope.base.fscommands from rope.base import exceptions, taskhandle, utils -from rope.base.fscommands import FileContent +from rope.base.fscommands import FileContent # type:ignore class Change: @@ -334,7 +334,7 @@ def _get_fscommands(self, resource): def write_file(self, resource, contents: Union[str, FileContent]): data: FileContent if not isinstance(contents, bytes): - data = rope.base.fscommands.unicode_to_file_data( + data = rope.base.fscommands.unicode_to_file_data( # type:ignore contents, newlines=resource.newlines, ) diff --git a/rope/base/oi/soa.py b/rope/base/oi/soa.py index df60c6fbb..f576cab9c 100644 --- a/rope/base/oi/soa.py +++ b/rope/base/oi/soa.py @@ -1,8 +1,20 @@ +# type:ignore +from __future__ import annotations +from typing import Any, Union, TYPE_CHECKING + import rope.base.ast import rope.base.oi.soi import rope.base.pynames from rope.base import arguments, evaluate, nameanalyze, pyobjects +if TYPE_CHECKING: + from rope.base.pyobjects import PyFunction + from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction + + PyFunc = Union[PyFunction, DefinedPyFunction] +else: + PyFunc = Any + def analyze_module(pycore, pymodule, should_analyze, search_subscopes, followed_calls): """Analyze `pymodule` for static object inference @@ -25,7 +37,7 @@ def _analyze_node(pycore, pydefined, should_analyze, search_subscopes, followed_ return_true = lambda pydefined: True return_false = lambda pydefined: False - def _follow(pyfunction): + def _follow(pyfunction: PyFunc) -> None: _analyze_node( pycore, pyfunction, return_true, return_false, new_followed_calls ) @@ -70,7 +82,7 @@ def _Call(self, node): return self._call(pyfunction, args) - def _args_with_self(self, primary, self_pyname, pyfunction, node): + def _args_with_self(self, primary, self_pyname, pyfunction: PyFunc, node: None): base_args = arguments.create_arguments(primary, pyfunction, node, self.scope) return arguments.MixedArguments(self_pyname, base_args, self.scope) diff --git a/rope/base/oi/soi.py b/rope/base/oi/soi.py index 4495795db..34be4c29a 100644 --- a/rope/base/oi/soi.py +++ b/rope/base/oi/soi.py @@ -4,15 +4,28 @@ package. """ +from __future__ import annotations +from typing import Any, Union, TYPE_CHECKING import rope.base.builtins # Use full qualification for clarity. from rope.base import arguments, evaluate, pynames, pyobjects, utils from rope.base.oi.type_hinting.factory import get_type_hinting_factory +if TYPE_CHECKING: + import ast + from rope.base.pyobjects import PyFunction + from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction + + Node = ast.AST + PyFunc = Union[PyFunction, DefinedPyFunction] +else: + Node = Any + PyFunc = Any + _ignore_inferred = utils.ignore_exception(pyobjects.IsBeingInferredError) @_ignore_inferred -def infer_returned_object(pyfunction, args): +def infer_returned_object(pyfunction: PyFunc, args): """Infer the `PyObject` this `PyFunction` returns after calling""" object_info = pyfunction.pycore.object_info result = object_info.get_exact_returned(pyfunction, args) @@ -36,7 +49,7 @@ def infer_returned_object(pyfunction, args): @_ignore_inferred -def infer_parameter_objects(pyfunction): +def infer_parameter_objects(pyfunction: PyFunc): """Infer the `PyObject` of parameters of this `PyFunction`""" object_info = pyfunction.pycore.object_info result = object_info.get_parameter_objects(pyfunction) @@ -85,7 +98,7 @@ def infer_assigned_object(pyname): return result -def get_passed_objects(pyfunction, parameter_index): +def get_passed_objects(pyfunction: PyFunc, parameter_index: int) -> Any: object_info = pyfunction.pycore.object_info result = object_info.get_passed_objects(pyfunction, parameter_index) if not result: diff --git a/rope/base/oi/type_hinting/utils.py b/rope/base/oi/type_hinting/utils.py index 988e6697a..c7fef1bc5 100644 --- a/rope/base/oi/type_hinting/utils.py +++ b/rope/base/oi/type_hinting/utils.py @@ -1,3 +1,4 @@ +# type:ignore import logging from typing import Optional, Tuple diff --git a/rope/base/pynamesdef.py b/rope/base/pynamesdef.py index 6bda46f22..b7f2c8bcb 100644 --- a/rope/base/pynamesdef.py +++ b/rope/base/pynamesdef.py @@ -1,4 +1,6 @@ +from __future__ import annotations import contextlib +from typing import Any, Union, TYPE_CHECKING import rope.base.oi.soi import rope.base.pyobjects @@ -8,6 +10,14 @@ assert g +if TYPE_CHECKING: + from rope.base.pyobjects import PyFunction + from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction + + PyFunc = Union[PyFunction, DefinedPyFunction] +else: + PyFunc = Any + class DefinedName(pynames.DefinedName): pass @@ -53,7 +63,7 @@ class UnboundName(pynames.UnboundName): class ParameterName(pynames.ParameterName): - def __init__(self, pyfunction, index): + def __init__(self, pyfunction: PyFunc, index: int) -> None: self.pyfunction = pyfunction self.index = index if 1: # trace diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 302a74c80..7ed73e3e7 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -341,7 +341,8 @@ def __init__(self, pycore, ast_node, resource): @property def absolute_name(self) -> str: - return self.get_name() + # mypy error? + return self.get_name() # type:ignore def _get_concluded_data(self): new_data = _ConcludedData() diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index e96b15548..fbc1d2ea3 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -1,3 +1,4 @@ +from typing import Any import rope.base.builtins import rope.base.codeanalyze import rope.base.evaluate @@ -19,6 +20,9 @@ assert g +# This can't be fixed until we distinguish between stdlib.ast and rope.base.ast. +Node = Any + class PyFunction(pyobjects.PyFunction): def __init__(self, pycore, ast_node, parent): @@ -458,7 +462,7 @@ def _ClassDef(self, node): ) self.defineds.append(pyclass) - def _FunctionDef(self, node): + def _FunctionDef(self, node: Node): pyfunction = PyFunction(self.pycore, node, self.owner_object) for decorator in pyfunction.decorators: diff --git a/rope/contrib/autoimport/sqlite.py b/rope/contrib/autoimport/sqlite.py index 2f9744f15..bbb17cf96 100644 --- a/rope/contrib/autoimport/sqlite.py +++ b/rope/contrib/autoimport/sqlite.py @@ -1,3 +1,4 @@ +# type:ignore """AutoImport module for rope.""" import contextlib diff --git a/rope/contrib/autoimport/utils.py b/rope/contrib/autoimport/utils.py index 6d8f9b414..ba10e6952 100644 --- a/rope/contrib/autoimport/utils.py +++ b/rope/contrib/autoimport/utils.py @@ -4,7 +4,7 @@ from collections import OrderedDict from typing import Generator, List, Optional, Tuple -from rope.base.project import Project +from rope.base.project import Project # type:ignore from .defs import ModuleCompiled, ModuleFile, ModuleInfo, Package, PackageType, Source diff --git a/rope/contrib/generate.py b/rope/contrib/generate.py index 2e6c81b49..e535b1ec6 100644 --- a/rope/contrib/generate.py +++ b/rope/contrib/generate.py @@ -17,7 +17,7 @@ if TYPE_CHECKING: from typing import Literal, Optional - from rope.base.project import Project + from rope.base.project import Project # type:ignore from rope.base.resources import Resource GenerateKind = Literal[ diff --git a/rope/refactor/importutils/module_imports.py b/rope/refactor/importutils/module_imports.py index 508934a89..b1dd5463d 100644 --- a/rope/refactor/importutils/module_imports.py +++ b/rope/refactor/importutils/module_imports.py @@ -479,7 +479,7 @@ def __init__(self, pymodule: PyModule, wanted_pyobject: PyObject): for name, pyname in pymodule._get_structural_attributes().items(): if not isinstance(pyname, (pynames.ImportedName, pynames.ImportedModule)): self.names.add(name) - wanted_scope = wanted_pyobject.get_scope() + wanted_scope = wanted_pyobject.get_scope() # type:ignore self.start = wanted_scope.get_start() self.end = wanted_scope.get_end() + 1 From f9fbbbce1952f88455fccb20e597d140d405f10c Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 13:09:45 -0600 Subject: [PATCH 76/99] Improve annotations --- rope/base/oi/soa.py | 2 +- rope/base/oi/type_hinting/utils.py | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/rope/base/oi/soa.py b/rope/base/oi/soa.py index 6bd513d1b..36614e4ef 100644 --- a/rope/base/oi/soa.py +++ b/rope/base/oi/soa.py @@ -1,6 +1,6 @@ # type:ignore from __future__ import annotations -from typing import Any, Union, TYPE_CHECKING +from typing import Any, Callable, Union, TYPE_CHECKING import rope.base.ast import rope.base.oi.soi diff --git a/rope/base/oi/type_hinting/utils.py b/rope/base/oi/type_hinting/utils.py index a97d7de41..6e4e0201c 100644 --- a/rope/base/oi/type_hinting/utils.py +++ b/rope/base/oi/type_hinting/utils.py @@ -1,12 +1,24 @@ # type:ignore import logging -from typing import Optional, Tuple +from typing import Any, Optional, Tuple, Union +from typing import TYPE_CHECKING import rope.base.utils as base_utils from rope.base import evaluate from rope.base.exceptions import AttributeNotFoundError from rope.base.pyobjects import PyClass, PyDefinedObject, PyFunction, PyObject +if TYPE_CHECKING: + from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction + from rope.base.pyscopes import Scope + + PyFunc = Union[PyFunction, DefinedPyFunction] + PyObj = Union[PyObject, PyDefinedObject] +else: + PyFunc = Any + PyObj = Any + Scope = Any + def get_super_func(pyfunc): if not isinstance(pyfunc.parent, PyClass): @@ -75,8 +87,7 @@ def get_mro(pyclass): def resolve_type( type_name: str, - pyobject: PyDefinedObject, - type_name: str, pyobject: PyObject + pyobject: PyObj, ### ) -> Optional[Tuple[PyDefinedObject, PyObject]]: """ Find proper type object from its name. From 1bd44c8b358015a2b6ab9459e707d5f28c414cc7 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 13:47:42 -0600 Subject: [PATCH 77/99] Remove g --- rope/base/ast.py | 8 ----- rope/base/builtins.py | 6 ---- rope/base/oi/type_hinting/utils.py | 13 +++---- rope/base/project.py | 7 ---- rope/base/pycore.py | 10 +----- rope/base/pynames.py | 24 ++----------- rope/base/pynamesdef.py | 11 ------ rope/base/pyobjects.py | 55 ------------------------------ rope/base/pyobjectsdef.py | 55 ++---------------------------- rope/base/pyscopes.py | 41 ---------------------- rope/base/utils/__init__.py | 47 ++++--------------------- ropetest/objectinfertest.py | 4 --- 12 files changed, 18 insertions(+), 263 deletions(-) diff --git a/rope/base/ast.py b/rope/base/ast.py index 15c675b8f..fcb5996b6 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -4,10 +4,6 @@ from rope.base import fscommands -from rope.base.utils import tracing_utils as g - -assert g - try: from ast import _const_node_type_names # type:ignore except ImportError: @@ -67,10 +63,6 @@ def visit(self, node): """Modified from ast.NodeVisitor to match rope's existing Visitor implementation""" method = "_" + node.__class__.__name__ visitor = getattr(self, method, self.generic_visit) - if 0: # trace - module, name = visitor.__module__, visitor.__name__ - if name != "generic_visit": - print(g.format("visit", module, name)) return visitor(node) diff --git a/rope/base/builtins.py b/rope/base/builtins.py index 6bffbeaf3..151c64742 100644 --- a/rope/base/builtins.py +++ b/rope/base/builtins.py @@ -5,10 +5,6 @@ import rope.base.evaluate from rope.base import arguments, ast, pynames, pyobjects, utils -from rope.base.utils import tracing_utils as g - -assert g - class BuiltinModule(pyobjects.AbstractModule): def __init__(self, name, pycore=None, initial={}): @@ -16,8 +12,6 @@ def __init__(self, name, pycore=None, initial={}): self.name = name self.pycore = pycore self.initial = initial - if 0: # trace - print(g.format_ctor("builtins.BuiltinModule", __file__), name) parent = None diff --git a/rope/base/oi/type_hinting/utils.py b/rope/base/oi/type_hinting/utils.py index 6e4e0201c..d09829250 100644 --- a/rope/base/oi/type_hinting/utils.py +++ b/rope/base/oi/type_hinting/utils.py @@ -1,6 +1,6 @@ # type:ignore import logging -from typing import Any, Optional, Tuple, Union +from typing import Any, Optional, Union from typing import TYPE_CHECKING import rope.base.utils as base_utils @@ -9,13 +9,13 @@ from rope.base.pyobjects import PyClass, PyDefinedObject, PyFunction, PyObject if TYPE_CHECKING: - from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction + # from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction from rope.base.pyscopes import Scope - PyFunc = Union[PyFunction, DefinedPyFunction] + # PyFunc = Union[PyFunction, DefinedPyFunction] PyObj = Union[PyObject, PyDefinedObject] else: - PyFunc = Any + # PyFunc = Any PyObj = Any Scope = Any @@ -85,10 +85,7 @@ def get_mro(pyclass): return class_list -def resolve_type( - type_name: str, - pyobject: PyObj, ### -) -> Optional[Tuple[PyDefinedObject, PyObject]]: +def resolve_type(type_name: str, pyobject: PyObj) -> Optional[PyObj]: """ Find proper type object from its name. """ diff --git a/rope/base/project.py b/rope/base/project.py index f2b674023..ae104ade0 100644 --- a/rope/base/project.py +++ b/rope/base/project.py @@ -14,7 +14,6 @@ from rope.base.prefs import Prefs, get_config # type:ignore from rope.base.resources import File, Folder, _ResourceMatcher -from rope.base.utils import tracing_utils as g ### try: import cPickle as pickle # type:ignore @@ -235,12 +234,6 @@ def __repr__(self) -> str: self.address, ) - def description(self) -> str: - if 1: # trace - file_name = g.short_file_name(self.address) - return f"{self.__class__.__module__}.{self.__class__.__name__}:{file_name}" - return "" - @utils.deprecated("Delete once deprecated functions are gone") def _init_source_folders(self): for path in self.prefs.get("source_folders", []): diff --git a/rope/base/pycore.py b/rope/base/pycore.py index 852e6a25c..1f5b46fe0 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -13,8 +13,6 @@ import rope.base.resources from rope.base import builtins, exceptions, pyobjectsdef, stdmods, taskhandle, utils -from rope.base.utils import tracing_utils as g - if TYPE_CHECKING: from rope.base.pyscopes import Scope from rope.base.resources import Resource @@ -30,12 +28,6 @@ def __init__(self, project): self.object_info = rope.base.oi.objectinfo.ObjectInfoManager(project) self._init_python_files() self._init_automatic_soa() - if 0: # trace - # This will be the first enabled print statement, - # if there is no trace in any setUp method. - print("\n") - if 0: # trace - print(g.format_ctor("PyCore", __file__)) def _init_python_files(self): self.python_matcher = None @@ -219,7 +211,7 @@ def analyze_module( followed_calls = self.project.prefs.get("soa_followed_calls", 0) pymodule = self.resource_to_pyobject(resource) self.module_cache.forget_all_data() - rope.base.oi.soa.analyze_module( + rope.base.oi.soa.analyze_module( # type:ignore self, pymodule, should_analyze, search_subscopes, followed_calls ) diff --git a/rope/base/pynames.py b/rope/base/pynames.py index 422e9fd03..5e367e2ab 100644 --- a/rope/base/pynames.py +++ b/rope/base/pynames.py @@ -11,20 +11,12 @@ from rope.base import pyobjectsdef from rope.base.pyobjects import PyObject -from rope.base.utils import tracing_utils as g ### - -assert g - class PyName: """References to `PyObject` inside python programs""" - ### Holds analysis of assignments statements. - - if 1: # trace (temp ctor) - - def __init__(self): - print(g.format_ctor("***PyName**", __file__)) + # Holds analysis of assignments statements. + pass def get_object(self) -> Optional[PyObject]: """Return the `PyObject` object referenced by this `PyName`""" @@ -38,8 +30,6 @@ def get_definition_location(self) -> Optional[Tuple[Any, int]]: class DefinedName(PyName): def __init__(self, pyobject): self.pyobject = pyobject - if 1: # trace - print(g.format_ctor("DefinedName", __file__), f"pyobject: {pyobject!r}") def get_object(self): return self.pyobject @@ -203,17 +193,7 @@ def get_definition_location(self): def _get_concluded_data(module): if module is None: - g.trace("(*** pynames function): instantiate") return rope.base.pyobjects._ConcludedData() - if 0: - # Callers... - # test_simple_type_inferencing,__getitem__,get_name,__getitem__, - # get_attribute,newfunc,_get_structural_attributes,_create_structural_attributes, - # visit,_Assign,visit,_Assign,visit,_Name,_assigned,_assigned,__init__ - print("") - g.trace("(*** pynames function): return module._get_concluded_data") - g.trace(g.callers(17)) - g.trace(module._ekr_dump_concluded_data()) return module._get_concluded_data() diff --git a/rope/base/pynamesdef.py b/rope/base/pynamesdef.py index b7f2c8bcb..2ab145b89 100644 --- a/rope/base/pynamesdef.py +++ b/rope/base/pynamesdef.py @@ -6,10 +6,6 @@ import rope.base.pyobjects from rope.base import pynames, utils -from rope.base.utils import tracing_utils as g - -assert g - if TYPE_CHECKING: from rope.base.pyobjects import PyFunction from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction @@ -32,11 +28,6 @@ def __init__(self, lineno=None, module=None, pyobject=None): self._get_inferred, pynames._get_concluded_data(module) ) self.pyobject.set(pyobject) - if 1: # trace - print( - g.format_ctor("pynamesdef.AssignedName", __file__), - f"pyobject: {pyobject!r}", - ) @utils.prevent_recursion(lambda: None) def _get_inferred(self): @@ -66,8 +57,6 @@ class ParameterName(pynames.ParameterName): def __init__(self, pyfunction: PyFunc, index: int) -> None: self.pyfunction = pyfunction self.index = index - if 1: # trace - print(g.format_ctor("ParameterName", __file__), repr(pyfunction)) def get_object(self): result = self.pyfunction.get_parameter(self.index) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 7ed73e3e7..f19075a53 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -2,24 +2,11 @@ from rope.base import ast, exceptions, utils -from rope.base.utils import tracing_utils as g - -assert g - class PyObject: def __init__(self, type_): if type_ is None: type_ = self - - if 0: # trace - if not hasattr(self, "type") or type_ != self.type: - if "builtins" not in g.callers(): - print( - g.format_ctor("PyObject", __file__), - f"id: {id(self)}", - g.callers(2), - ) self.type = type_ def get_attributes(self): @@ -131,11 +118,6 @@ def get_unknown(): class AbstractClass(PyObject): - def __init__(self): - if 0: # trace !!!This trace disables all other traces!!! - print(g.format_ctor("AbstractClass", __file__)) - super().__init__(get_base_type("Type")) - def get_name(self): pass @@ -186,12 +168,6 @@ def __init__(self, pycore, ast_node, parent): self.concluded_attributes = self.get_module()._get_concluded_data() self.attributes = self.get_module()._get_concluded_data() self.defineds = None - if 1: # trace # trace - # print('') - print( - g.format_ctor("PyDefinedObject", __file__), - f"ast_node: {ast_node.__class__.__name__}", - ) def __repr__(self): return '<{}.{} "{}" at {}>'.format( @@ -297,26 +273,9 @@ class PyClass(PyDefinedObject, AbstractClass): class _ConcludedData: def __init__(self): self.data_ = None - if 0: # trace - ### - # import re - # pat = re.compile(r"_?[A-Z]") - # callers_s = ",".join([z for z in g.callers_list(20) if re.match(pat, z)]) - # print(g.format_ctor("_ConcludedData", __file__), f"id: {id(self)}", callers_s) - - print( - g.format_ctor("_ConcludedData", __file__), - f"id: {id(self)}", - g.callers(4), - ) def set(self, data): self.data_ = data - if 0: # trace: now done in the get_names methods of Scopes. - tag = f"_ConcludedData.set: {id(self)}" - n = 2 if isinstance(data, (dict, list, set)) else 4 - print(f"{tag} {data.__class__.__name__:<14}", g.callers(n)) - print(g.to_string(data)) def get(self): return self.data_ @@ -336,8 +295,6 @@ def __init__(self, pycore, ast_node, resource): self.concluded_data = [] AbstractModule.__init__(self) PyDefinedObject.__init__(self, pycore, ast_node, None) - if 0: # trace # trace - print(g.format_ctor("PyModule", __file__)) @property def absolute_name(self) -> str: @@ -356,18 +313,6 @@ def _forget_concluded_data(self): def get_resource(self): return self.resource - def _ekr_dump_concluded_data(self): - g.trace("(pyobjects._PyModule._ekr_dump_concluded_data)") - tag = self.get_name() - try: - for i, z in enumerate(self.concluded_data): - g.print_obj(f"{i:3} {z!s}", tag=tag) - # z._ekr_dump() - except TypeError: - z = self.concluded_data - g.print_obj(f"{z!s}", tag=tag) - # z._ekr_dump() - class PyModule(_PyModule): pass diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index fbc1d2ea3..53a487c01 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -16,10 +16,6 @@ utils, ) -from rope.base.utils import tracing_utils as g - -assert g - # This can't be fixed until we distinguish between stdlib.ast and rope.base.ast. Node = Any @@ -141,9 +137,6 @@ def __init__(self, pycore, ast_node, parent): rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent) self.parent = parent self._superclasses = self.get_module()._get_concluded_data() - if 1: # trace - print(g.format_ctor("PyClass", __file__), "node.name:", ast_node.name) - if 0: # trace # Overried po.PyDefinedObject.__repr__ @@ -205,8 +198,6 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): self.star_imports = [] self.visitor_class = _GlobalVisitor self.coding = fscommands.read_str_coding(self.source_code) - if 0: # trace - print(g.format_ctor("PyModule", __file__)) super().__init__(pycore, node, resource) def _init_source(self, pycore, source_code, resource): @@ -321,8 +312,8 @@ def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None self.type_hint = None - if 0: # trace - print(g.format_ctor("_AnnAssignVisitor", __file__)) + + def _AnnAssign(self, node): self.assigned_ast = node.value @@ -363,9 +354,6 @@ def _Slice(self, node): class _ExpressionVisitor(ast.RopeNodeVisitor): def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor - if 0: # trace - print(g.format_ctor("_ExpressionVisitor", __file__)) - def _assigned(self, name, assignment=None): self.scope_visitor._assigned(name, assignment) @@ -393,9 +381,6 @@ class _AssignVisitor(ast.RopeNodeVisitor): def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None - if 0: # trace - print(g.format_ctor("_AssignVisitor", __file__)) - # Assign(expr* targets, expr value, string? type_comment) def _Assign(self, node): @@ -442,9 +427,6 @@ def __init__(self, pycore, owner_object): self.owner_object = owner_object self.names = {} self.defineds = [] - if 0: # trace - print(g.format_ctor("_ScopeVisitor", __file__)) - def get_module(self): if self.owner_object is not None: return self.owner_object.get_module() @@ -454,12 +436,6 @@ def get_module(self): def _ClassDef(self, node): pyclass = PyClass(self.pycore, node, self.owner_object) self.names[node.name] = pynamesdef.DefinedName(pyclass) - if 1: - print("") - g.trace( - f"ScopeVisitor._ClassDef: NEW DefinedName: {node.name}: " - f"{self.names[node.name]}\n" - ) self.defineds.append(pyclass) def _FunctionDef(self, node: Node): @@ -487,12 +463,7 @@ def _eval(type_=type_, arg=arg): else: self.names[node.name] = pynamesdef.DefinedName(pyfunction) - if 1: - print("") - g.trace( - f"ScopeVisitor._FunctionDef: NEW DefinedName: {node.name}: " - f"{self.names[node.name]}\n" - ) + self.defineds.append(pyfunction) def _AsyncFunctionDef(self, node): @@ -519,17 +490,9 @@ def _assigned(self, name, assignment): pyname = self.names.get(name, None) if pyname is None: pyname = pynamesdef.AssignedName(module=self.get_module()) - if 1: # trace - print("") - g.trace(f"ScopeVisitor._assigned: NEW pyname: {pyname}") if isinstance(pyname, pynamesdef.AssignedName): if assignment is not None: pyname.assignments.append(assignment) - if 1: # trace - g.trace( - f"ScopeVisitor._assigned: NEW append to assignments: {assignment}" - ) - # print("") self.names[name] = pyname def _update_evaluated( @@ -665,9 +628,6 @@ def __init__(self, pycore, owner_object): super().__init__(pycore, owner_object) self.returned_asts = [] self.generator = False - if 0: # trace - print(g.format_ctor("_FunctionVisitor", __file__)) - def _Return(self, node): if node.value is not None: self.returned_asts.append(node.value) @@ -682,9 +642,6 @@ class _ClassInitVisitor(_AssignVisitor): def __init__(self, scope_visitor, self_name): super().__init__(scope_visitor) self.self_name = self_name - if 0: # trace - print(g.format_ctor("_ClassInitVisitor", __file__)) - def _Attribute(self, node): if not isinstance(node.ctx, ast.Store): return @@ -732,10 +689,4 @@ def get_names(self): for name in imported: if not name.startswith("_"): result[name] = pynamesdef.ImportedName(self.imported_module, name) - if 1: # trace - data = result - tag = "StarImport.get_names" - # n = 2 if isinstance(data, (dict, list, set)) else 4 - print(f"{tag:>20} {data.__class__.__name__:<14}", g.callers(4)) - print(g.to_string(data)) return result diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index a11d37957..565541903 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -2,10 +2,6 @@ from rope.base import ast, codeanalyze, exceptions, pynames, utils from rope.refactor import patchedast -from rope.base.utils import tracing_utils as g - -assert g - class Scope: def __init__(self, pycore, pyobject, parent_scope): @@ -15,18 +11,6 @@ def __init__(self, pycore, pyobject, parent_scope): def get_names(self): """Return the names defined or imported in this scope""" - if 1: # trace - data = self.pyobject.get_attributes() - # print("Scope.get_names", g.callers(6)) - try: - # Fails in general... - for z in data: - print( - f"{z:>10} {data[z].__class__.__name__:<12} pyobject: {data[z].pyobject}" - ) - print("") - except Exception: - print(f"\n{g.to_string(data)}\n") return self.pyobject.get_attributes() def get_defined_names(self): @@ -163,12 +147,6 @@ def get_names(self): result = dict(self.builtin_names) result.update(super().get_names()) self.names.set(result) - if 0: # trace - data = self.names.get() - tag = "GlobalScope.get_names" - # n = 2 if isinstance(data, (dict, list, set)) else 4 - print(f"{tag:>20} {data.__class__.__name__:<14}", g.callers(4)) - print(g.to_string(data)) return self.names.get() def get_inner_scope_for_line(self, lineno, indents=None): @@ -201,13 +179,6 @@ def _get_names(self): return self.names def get_names(self): - if 1: # trace - data = self._get_names() - tag = "ComprehensionScope.get_names" - # n = 2 if isinstance(data, (dict, list, set)) else 4 - print(f"{tag:>20} {data.__class__.__name__:<14}", g.callers(4)) - print(g.to_string(data, indent=4)) - return self._get_names() def _visit_comprehension(self): @@ -264,12 +235,6 @@ def _is_generator(self): return self.is_generator def get_names(self): - if 1: # trace - data = self._get_names() - tag = "FunctionScope.get_names" - # n = 2 if isinstance(data, (dict, list, set)) else 4 - print(f"{tag:>20} {data.__class__.__name__:<14}", g.callers(4)) - print(g.to_string(data)) return self._get_names() def _create_scopes(self): @@ -393,12 +358,6 @@ def __init__(self, pycore, parent_scope, names): self.names = names def get_names(self): - if 1: # trace - data = self.names - tag = "TemporaryScope.get_names" - # n = 2 if isinstance(data, (dict, list, set)) else 4 - print(f"{tag:>20} {data.__class__.__name__:<14}", g.callers(4)) - print(g.to_string(data)) return self.names def get_defined_names(self): diff --git a/rope/base/utils/__init__.py b/rope/base/utils/__init__.py index a4b8974ea..393826c27 100644 --- a/rope/base/utils/__init__.py +++ b/rope/base/utils/__init__.py @@ -1,9 +1,4 @@ import sys -import warnings - -from rope.base.utils import tracing_utils as g - -assert g def saveit(func): @@ -21,39 +16,13 @@ def saveit(func): # """A decorator that caches the return value of a function""" ivar_name = f"_{func.__name__}" - if 1: # Original version: - - def _wrapper(self, *args, **kwargs): - if not hasattr(self, ivar_name): - # Instantiate the singleton object. - obj = func(self, *args, **kwargs) - setattr(self, ivar_name, obj) - # Return the value of the ivar. - return getattr(self, ivar_name) - - else: - - def _wrapper(self, *args, **kwargs): - tag = "@saveit" - if not hasattr(self, ivar_name): - # Instantiate the object. - obj = func(self, *args, **kwargs) - if 1: # Tracing version. - injected_name = f"{self.__class__.__name__}.{ivar_name}" - func_s = repr(func).replace("30} = {description}") - else: - print("") - g.print_obj( - obj, tag=f"{tag} ivar: {injected_name} = {description}" - ) - setattr(self, ivar_name, obj) - # Original. - # setattr(self, ivar_name, func(self, *args, **kwds)) - return getattr(self, ivar_name) + def _wrapper(self, *args, **kwargs): + if not hasattr(self, ivar_name): + # Instantiate the singleton object. + obj = func(self, *args, **kwargs) + setattr(self, ivar_name, obj) + # Return the value of the ivar. + return getattr(self, ivar_name) return _wrapper @@ -104,8 +73,6 @@ def _decorator(func, message=message): message = "%s is deprecated" % func.__name__ def newfunc(*args, **kwds): - if 0: ### - warnings.warn(message, DeprecationWarning, stacklevel=2) return func(*args, **kwds) return newfunc diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 99f509b09..d1746d10f 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -5,10 +5,6 @@ from rope.base import libutils from ropetest import testutils -from rope.base.utils import tracing_utils as g - -assert g - class ObjectInferTest(unittest.TestCase): def setUp(self): """ From 27bb2811ec5e56b6631cd053d759e0ade101d423 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 13:53:51 -0600 Subject: [PATCH 78/99] Fix glitches --- rope/base/pyobjects.py | 3 +++ rope/base/pyobjectsdef.py | 9 +++++--- ropetest/objectinfertest.py | 42 +------------------------------------ 3 files changed, 10 insertions(+), 44 deletions(-) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index f19075a53..087d52f65 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -118,6 +118,9 @@ def get_unknown(): class AbstractClass(PyObject): + def __init__(self): + super().__init__(get_base_type("Type")) + def get_name(self): pass diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index 53a487c01..f34a25756 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -137,6 +137,7 @@ def __init__(self, pycore, ast_node, parent): rope.base.pyobjects.PyDefinedObject.__init__(self, pycore, ast_node, parent) self.parent = parent self._superclasses = self.get_module()._get_concluded_data() + if 0: # trace # Overried po.PyDefinedObject.__repr__ @@ -313,8 +314,6 @@ def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.assigned_ast = None self.type_hint = None - - def _AnnAssign(self, node): self.assigned_ast = node.value self.type_hint = node.annotation @@ -354,6 +353,7 @@ def _Slice(self, node): class _ExpressionVisitor(ast.RopeNodeVisitor): def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor + def _assigned(self, name, assignment=None): self.scope_visitor._assigned(name, assignment) @@ -381,6 +381,7 @@ class _AssignVisitor(ast.RopeNodeVisitor): def __init__(self, scope_visitor: ast.RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None + # Assign(expr* targets, expr value, string? type_comment) def _Assign(self, node): @@ -427,6 +428,7 @@ def __init__(self, pycore, owner_object): self.owner_object = owner_object self.names = {} self.defineds = [] + def get_module(self): if self.owner_object is not None: return self.owner_object.get_module() @@ -463,7 +465,6 @@ def _eval(type_=type_, arg=arg): else: self.names[node.name] = pynamesdef.DefinedName(pyfunction) - self.defineds.append(pyfunction) def _AsyncFunctionDef(self, node): @@ -628,6 +629,7 @@ def __init__(self, pycore, owner_object): super().__init__(pycore, owner_object) self.returned_asts = [] self.generator = False + def _Return(self, node): if node.value is not None: self.returned_asts.append(node.value) @@ -642,6 +644,7 @@ class _ClassInitVisitor(_AssignVisitor): def __init__(self, scope_visitor, self_name): super().__init__(scope_visitor) self.self_name = self_name + def _Attribute(self, node): if not isinstance(node.ctx, ast.Store): return diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index d1746d10f..e277ac2fa 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -29,51 +29,11 @@ class Sample(object): a_var = Sample() """) - # setUp creates self.project. - print('') - print('after: setUp\n') - print('self.project:', self.project.description()) - - print('\ndo: scope = libutils.get_string_scope(...)\n') - scope = libutils.get_string_scope(self.project, code) - - print('') - print(' scope:', scope) - print('scope.pyobject:', scope.pyobject) - - print('\ndo: sample_scope = scope["Sample"]\n') - sample_scope = scope["Sample"] - - print('\nsample_scope:', sample_scope) - - print('\ndo: sample_scope.get_object()') - sample_class = sample_scope.get_object() - - print('\nsample_class:', sample_class) - - print('\ndo: na_var_scope = scope["a_var"]\n') - - a_var_scope = scope["a_var"] - - print('a_var_scope:', a_var_scope) - - print('\ndo: a_var = a_var_scope.get_object()\n') - - a_var = a_var_scope.get_object() - - print('') - print(' a_var:', a_var) - print('a_var.get_type():', a_var.get_type()) - - print('\ndo: self.assertEqual(sample_class, a_var.get_type())') - + a_var = scope["a_var"].get_object() self.assertEqual(sample_class, a_var.get_type()) - - print('') - print('sample_class:', sample_class) def test_simple_type_inferencing_classes_defined_in_holding_scope(self): code = dedent("""\ class Sample(object): From 4c35e26d8aada14ba192c266e59677b149869655 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 14:03:19 -0600 Subject: [PATCH 79/99] Improve annations in pyobjectsdef.py. We must import stdlib.ast separately! --- rope/base/pyobjectsdef.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index f34a25756..bd91ef848 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -1,4 +1,5 @@ -from typing import Any +import ast + import rope.base.builtins import rope.base.codeanalyze import rope.base.evaluate @@ -7,7 +8,7 @@ import rope.base.pyscopes from rope.base import ( arguments, - ast, + # ast, exceptions, fscommands, nameanalyze, @@ -16,8 +17,7 @@ utils, ) -# This can't be fixed until we distinguish between stdlib.ast and rope.base.ast. -Node = Any +from rope.base.ast import RopeNodeVisitor class PyFunction(pyobjects.PyFunction): @@ -194,7 +194,7 @@ def __init__(self, pycore, source=None, resource=None, force_errors=False): raise else: source = "\n" - node = ast.parse("\n") + node = rope.base.ast.parse("\n") self.source_code = source self.star_imports = [] self.visitor_class = _GlobalVisitor @@ -214,7 +214,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 = rope.base.ast.parse(source_bytes, filename=filename) except SyntaxError as e: raise exceptions.ModuleSyntaxError(filename, e.lineno, e.msg) except UnicodeDecodeError as e: @@ -256,7 +256,7 @@ def __init__(self, pycore, resource=None, force_errors=False): init_dot_py, force_errors=force_errors ).get_ast() else: - ast_node = ast.parse("\n") + ast_node = rope.base.ast.parse("\n") super().__init__(pycore, ast_node, resource) def _create_structural_attributes(self): @@ -308,8 +308,8 @@ def get_name(self): return rope.base.libutils.modname(self.resource) if self.resource else "" -class _AnnAssignVisitor(ast.RopeNodeVisitor): - def __init__(self, scope_visitor: ast.RopeNodeVisitor): +class _AnnAssignVisitor(RopeNodeVisitor): + def __init__(self, scope_visitor: RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None self.type_hint = None @@ -350,8 +350,8 @@ def _Slice(self, node): pass -class _ExpressionVisitor(ast.RopeNodeVisitor): - def __init__(self, scope_visitor: ast.RopeNodeVisitor): +class _ExpressionVisitor(RopeNodeVisitor): + def __init__(self, scope_visitor: RopeNodeVisitor): self.scope_visitor = scope_visitor def _assigned(self, name, assignment=None): @@ -377,8 +377,8 @@ def _NamedExpr(self, node): self.visit(node.value) -class _AssignVisitor(ast.RopeNodeVisitor): - def __init__(self, scope_visitor: ast.RopeNodeVisitor): +class _AssignVisitor(RopeNodeVisitor): + def __init__(self, scope_visitor: RopeNodeVisitor): self.scope_visitor = scope_visitor self.assigned_ast = None @@ -440,7 +440,7 @@ def _ClassDef(self, node): self.names[node.name] = pynamesdef.DefinedName(pyclass) self.defineds.append(pyclass) - def _FunctionDef(self, node: Node): + def _FunctionDef(self, node: ast.FunctionDef): pyfunction = PyFunction(self.pycore, node, self.owner_object) for decorator in pyfunction.decorators: From 942c5c9dce76f4aac65a8cbd2b2aac0fca641e1d Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 14:25:32 -0600 Subject: [PATCH 80/99] More annotations --- rope/base/arguments.py | 3 --- rope/base/oi/soa.py | 11 ++++++----- rope/base/pynamesdef.py | 2 -- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/rope/base/arguments.py b/rope/base/arguments.py index fe217b05c..d271f5e44 100644 --- a/rope/base/arguments.py +++ b/rope/base/arguments.py @@ -9,9 +9,6 @@ from rope.base.pyscopes import Scope PyFunc = Union[PyFunction, DefinedPyFunction] -else: - PyFunc = Any - Scope = Any Node = ast.AST diff --git a/rope/base/oi/soa.py b/rope/base/oi/soa.py index 36614e4ef..2d250bed2 100644 --- a/rope/base/oi/soa.py +++ b/rope/base/oi/soa.py @@ -1,6 +1,6 @@ # type:ignore from __future__ import annotations -from typing import Any, Callable, Union, TYPE_CHECKING +from typing import Callable, Union, TYPE_CHECKING import rope.base.ast import rope.base.oi.soi @@ -8,12 +8,13 @@ from rope.base import arguments, evaluate, nameanalyze, pyobjects if TYPE_CHECKING: + from rope.base.pycore import PyCore from rope.base.pyobjects import PyFunction from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction PyFunc = Union[PyFunction, DefinedPyFunction] -else: - PyFunc = Any +# # # else: +# # # PyFunc = Any def analyze_module( @@ -29,8 +30,8 @@ def analyze_module( def _analyze_node( - pycore, - pydefined, + pycore: PyCore, + pydefined: DefinedPyFunction, should_analyze: Callable, search_subscopes: Callable, followed_calls: bool, diff --git a/rope/base/pynamesdef.py b/rope/base/pynamesdef.py index 2ab145b89..0006c7435 100644 --- a/rope/base/pynamesdef.py +++ b/rope/base/pynamesdef.py @@ -11,8 +11,6 @@ from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction PyFunc = Union[PyFunction, DefinedPyFunction] -else: - PyFunc = Any class DefinedName(pynames.DefinedName): From ef2e27b48efb30f0fc93cca14156715e0432e3b8 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 14:49:42 -0600 Subject: [PATCH 81/99] Fix annotations after enabling same in soa.py and type_hinting/utils.py --- rope/base/oi/soa.py | 26 +++++++++++++------------- rope/base/oi/soi.py | 3 --- rope/base/oi/type_hinting/utils.py | 22 ++++++---------------- 3 files changed, 19 insertions(+), 32 deletions(-) diff --git a/rope/base/oi/soa.py b/rope/base/oi/soa.py index 2d250bed2..6a8325adf 100644 --- a/rope/base/oi/soa.py +++ b/rope/base/oi/soa.py @@ -1,8 +1,7 @@ -# type:ignore from __future__ import annotations +import ast from typing import Callable, Union, TYPE_CHECKING -import rope.base.ast import rope.base.oi.soi import rope.base.pynames from rope.base import arguments, evaluate, nameanalyze, pyobjects @@ -11,10 +10,9 @@ from rope.base.pycore import PyCore from rope.base.pyobjects import PyFunction from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction + from rope.base.pynames import PyName PyFunc = Union[PyFunction, DefinedPyFunction] -# # # else: -# # # PyFunc = Any def analyze_module( @@ -34,7 +32,7 @@ def _analyze_node( pydefined: DefinedPyFunction, should_analyze: Callable, search_subscopes: Callable, - followed_calls: bool, + followed_calls: int, ) -> None: if search_subscopes(pydefined): for scope in pydefined.get_scope().get_scopes(): @@ -46,13 +44,13 @@ def _analyze_node( return_true = lambda pydefined: True return_false = lambda pydefined: False - def _follow(pyfunction: PyFunc) -> None: + def _follow(pyfunction: DefinedPyFunction) -> None: _analyze_node( pycore, pyfunction, return_true, return_false, new_followed_calls ) visitor = SOAVisitor(pycore, pydefined, _follow if followed_calls else None) - for child in rope.base.ast.iter_child_nodes(pydefined.get_ast()): + for child in ast.iter_child_nodes(pydefined.get_ast()): visitor.visit(child) @@ -70,7 +68,7 @@ def _ClassDef(self, node): pass def _Call(self, node): - for child in rope.base.ast.iter_child_nodes(node): + for child in ast.iter_child_nodes(node): self.visit(child) primary, pyname = evaluate.eval_node2(self.scope, node.func) if pyname is None: @@ -91,7 +89,9 @@ def _Call(self, node): return self._call(pyfunction, args) - def _args_with_self(self, primary, self_pyname, pyfunction: PyFunc, node: None): + def _args_with_self( + self, primary, self_pyname: PyName, pyfunction: PyFunc, node: ast.Call + ): base_args = arguments.create_arguments(primary, pyfunction, node, self.scope) return arguments.MixedArguments(self_pyname, base_args, self.scope) @@ -118,7 +118,7 @@ def _parameter_objects(self, pyfunction): ] def _AnnAssign(self, node): - for child in rope.base.ast.iter_child_nodes(node): + for child in ast.iter_child_nodes(node): self.visit(child) visitor = _SOAAssignVisitor() nodes = [] @@ -129,7 +129,7 @@ def _AnnAssign(self, node): self._evaluate_assign_value(node, nodes, type_hint=node.annotation) def _Assign(self, node): - for child in rope.base.ast.iter_child_nodes(node): + for child in ast.iter_child_nodes(node): self.visit(child) visitor = _SOAAssignVisitor() nodes = [] @@ -164,7 +164,7 @@ def __init__(self): self.nodes = [] def _added(self, node, levels): - if isinstance(node, rope.base.ast.Subscript) and isinstance( - node.slice, (rope.base.ast.Index, rope.base.ast.expr) + if isinstance(node, ast.Subscript) and isinstance( + node.slice, (ast.Index, ast.expr) ): self.nodes.append((node, levels)) diff --git a/rope/base/oi/soi.py b/rope/base/oi/soi.py index 34be4c29a..2f243c954 100644 --- a/rope/base/oi/soi.py +++ b/rope/base/oi/soi.py @@ -17,9 +17,6 @@ Node = ast.AST PyFunc = Union[PyFunction, DefinedPyFunction] -else: - Node = Any - PyFunc = Any _ignore_inferred = utils.ignore_exception(pyobjects.IsBeingInferredError) diff --git a/rope/base/oi/type_hinting/utils.py b/rope/base/oi/type_hinting/utils.py index d09829250..add35c8e0 100644 --- a/rope/base/oi/type_hinting/utils.py +++ b/rope/base/oi/type_hinting/utils.py @@ -1,23 +1,11 @@ -# type:ignore +# from __future__ import annotations import logging -from typing import Any, Optional, Union -from typing import TYPE_CHECKING +from typing import Optional import rope.base.utils as base_utils from rope.base import evaluate from rope.base.exceptions import AttributeNotFoundError -from rope.base.pyobjects import PyClass, PyDefinedObject, PyFunction, PyObject - -if TYPE_CHECKING: - # from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction - from rope.base.pyscopes import Scope - - # PyFunc = Union[PyFunction, DefinedPyFunction] - PyObj = Union[PyObject, PyDefinedObject] -else: - # PyFunc = Any - PyObj = Any - Scope = Any +from rope.base.pyobjects import PyClass, PyDefinedObject, PyFunction def get_super_func(pyfunc): @@ -85,7 +73,9 @@ def get_mro(pyclass): return class_list -def resolve_type(type_name: str, pyobject: PyObj) -> Optional[PyObj]: +def resolve_type( + type_name: str, pyobject: PyDefinedObject +) -> Optional[PyDefinedObject]: """ Find proper type object from its name. """ From cbff5531ecf880b61f7580caab3edc6fc702dab2 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 15:06:48 -0600 Subject: [PATCH 82/99] Add and refine annotations --- rope/base/arguments.py | 4 ++-- rope/base/oi/soa.py | 25 +++++++++++++++++-------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/rope/base/arguments.py b/rope/base/arguments.py index d271f5e44..d2ea58fc5 100644 --- a/rope/base/arguments.py +++ b/rope/base/arguments.py @@ -4,11 +4,11 @@ from rope.base import ast if TYPE_CHECKING: - from rope.base.pyobjects import PyFunction + from rope.base.pyobjects import AbstractFunction, PyFunction from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction from rope.base.pyscopes import Scope - PyFunc = Union[PyFunction, DefinedPyFunction] + PyFunc = Union[AbstractFunction, PyFunction, DefinedPyFunction] Node = ast.AST diff --git a/rope/base/oi/soa.py b/rope/base/oi/soa.py index 6a8325adf..648aba06d 100644 --- a/rope/base/oi/soa.py +++ b/rope/base/oi/soa.py @@ -1,6 +1,6 @@ from __future__ import annotations import ast -from typing import Callable, Union, TYPE_CHECKING +from typing import Callable, List, Union, TYPE_CHECKING import rope.base.oi.soi import rope.base.pynames @@ -8,11 +8,11 @@ if TYPE_CHECKING: from rope.base.pycore import PyCore - from rope.base.pyobjects import PyFunction + from rope.base.pyobjects import AbstractFunction, PyFunction from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction from rope.base.pynames import PyName - PyFunc = Union[PyFunction, DefinedPyFunction] + PyFunc = Union[AbstractFunction, PyFunction, DefinedPyFunction] def analyze_module( @@ -67,7 +67,7 @@ def _FunctionDef(self, node): def _ClassDef(self, node): pass - def _Call(self, node): + def _Call(self, node: ast.Call): for child in ast.iter_child_nodes(node): self.visit(child) primary, pyname = evaluate.eval_node2(self.scope, node.func) @@ -90,12 +90,16 @@ def _Call(self, node): self._call(pyfunction, args) def _args_with_self( - self, primary, self_pyname: PyName, pyfunction: PyFunc, node: ast.Call + self, + primary, + self_pyname: PyName, + pyfunction: PyFunc, + node: ast.Call, ): base_args = arguments.create_arguments(primary, pyfunction, node, self.scope) return arguments.MixedArguments(self_pyname, base_args, self.scope) - def _call(self, pyfunction, args): + def _call(self, pyfunction: DefinedPyFunction, args): if isinstance(pyfunction, pyobjects.PyFunction): if self.follow is not None: before = self._parameter_objects(pyfunction) @@ -111,7 +115,7 @@ def _call(self, pyfunction, args): if isinstance(pyfunction, rope.base.builtins.BuiltinFunction): pyfunction.get_returned_object(args) - def _parameter_objects(self, pyfunction): + def _parameter_objects(self, pyfunction: DefinedPyFunction): return [ pyfunction.get_parameter(i) for i in range(len(pyfunction.get_param_names(False))) @@ -138,7 +142,12 @@ def _Assign(self, node): nodes.extend(visitor.nodes) self._evaluate_assign_value(node, nodes) - def _evaluate_assign_value(self, node, nodes, type_hint=False): + def _evaluate_assign_value( + self, + node: Union[ast.Assign, ast.AnnAssign], + nodes: List, + type_hint: bool = False, + ) -> None: for subscript, levels in nodes: instance = evaluate.eval_node(self.scope, subscript.value) args_pynames = [evaluate.eval_node(self.scope, subscript.slice)] From d168b1419afba3160b4f3067ff7e056fafdf04d8 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 15:15:56 -0600 Subject: [PATCH 83/99] Remove rope/base/leoGlobals.py --- rope/base/leoGlobals.py | 227 ------------------------------------ ropetest/objectinfertest.py | 8 +- 2 files changed, 2 insertions(+), 233 deletions(-) delete mode 100644 rope/base/leoGlobals.py diff --git a/rope/base/leoGlobals.py b/rope/base/leoGlobals.py deleted file mode 100644 index 4196f1580..000000000 --- a/rope/base/leoGlobals.py +++ /dev/null @@ -1,227 +0,0 @@ -""" -Tracing and debugging functions from Leo. - -Duplicated here so that Rope's commit checks won't fail. -""" - -# from __future__ import annotations -import os -import sys -from typing import Any, Dict, List, Optional - - -def _callerName(n: int) -> str: - try: - # get the function name from the call stack. - f1 = sys._getframe(n) # The stack frame, n levels up. - code1 = f1.f_code # The code object - locals_ = f1.f_locals # The local namespace. - name = code1.co_name - # sfn = shortFilename(code1.co_filename) # The file name. - # line = code1.co_firstlineno - obj = locals_.get("self") - if obj and name == "__init__": - return f"{obj.__class__.__name__}.{name}" - return name - except ValueError: - # The stack is not deep enough OR - # sys._getframe does not exist on this platform. - return "" - except Exception: - return "" # "" - - -def caller(i: int = 1) -> str: - """Return the caller name i levels up the stack.""" - return callers(i + 1).split(",")[0] - - -def callers(n: int = 4) -> str: - """ - Return a string containing a comma-separated list of the calling - function's callers. - """ - # Be careful to call _callerName with smaller values of i first: - # sys._getframe throws ValueError if there are less than i entries. - i, result = 3, [] - while 1: - s = _callerName(n=i) - if s: - result.append(s) - if not s or len(result) >= n: - break - i += 1 - return ",".join(reversed(result)) - - -def callers_list(n: int = 4) -> List[str]: - """ - Return a string containing a comma-separated list of the calling - function's callers. - """ - # Be careful to call _callerName with smaller values of i first: - # sys._getframe throws ValueError if there are less than i entries. - i, result = 3, [] - while 1: - s = _callerName(n=i) - if s: - result.append(s) - if not s or len(result) >= n: - break - i += 1 - return list(reversed(result)) - - -def get_ctor_name(self: Any, file_name: str, width: int = 25): - """Return .:>width""" - class_name = self.__class__.__name__ - module_name = shortFileName(file_name).replace(".py", "") - combined_name = f"{module_name}.{class_name}" - padding = " " * max(0, 25 - len(combined_name)) - return f"{padding}{combined_name}" - - -def plural(obj: Any) -> str: - """Return "s" or "" depending on n.""" - if isinstance(obj, (list, tuple, str)): - n = len(obj) - else: - n = obj - return "" if n == 1 else "s" - - -def printObj(obj: Any, indent: str = "", tag: str = None) -> None: - """Pretty print any Python object""" - print(objToString(obj, indent=indent, tag=tag)) - - -def objToString( - obj: Any, indent: str = "", tag: Optional[str] = "", concise: bool = False -) -> str: - """ - Pretty print any Python object to a string. - - concise=False: (Legacy) return a detailed string. - concise=True: Return a summary string. - """ - if tag: - print(tag.strip()) - if concise: - r = repr(obj) - if obj is None: - return f"{indent}None" - if isinstance(obj, dict): - return f"{indent}dict: {len(obj.keys())} keys" - if isinstance(obj, list): - return f"{indent}list: {len(obj)} items plural(len(obj))" - if isinstance(obj, tuple): - return f"{indent}tuple: {len(obj)} item{plural(len(obj))}" - if "method" in r: - return f"{indent}method: {obj.__name__}" - if "class" in r: - return f"{indent}class" - if "module" in r: - return f"{indent}module" - return f"{indent}object: {obj!r}" - - # concise = False - if isinstance(obj, dict): - return dictToString(obj, indent=indent) - if isinstance(obj, list): - return listToString(obj, indent=indent) - if isinstance(obj, tuple): - return tupleToString(obj, indent=indent) - if isinstance(obj, str): - # Print multi-line strings as lists. - lines = splitLines(obj) - if len(lines) > 1: - return listToString(lines, indent=indent) - return f"{indent} {obj!r}" - - -def dictToString(d: Dict[str, str], indent: str = "", tag: Optional[str] = None) -> str: - """Pretty print a Python dict to a string.""" - # pylint: disable=unnecessary-lambda - if not d: - return "{}" - result = ["{\n"] - indent2 = indent + " " * 4 - n = 2 + len(indent) + max([len(repr(z)) for z in d.keys()]) - for i, key in enumerate(sorted(d, key=lambda z: repr(z))): - pad = " " * max(0, (n - len(repr(key)))) - result.append(f"{pad}{key}:") - result.append(objToString(d.get(key), indent=indent2)) - if i + 1 < len(d.keys()): - result.append(",") - result.append("\n") - result.append(indent + "}") - s = "".join(result) - return f"{tag}...\n{s}\n" if tag else s - - -def listToString(obj: Any, indent: str = "", tag: Optional[str] = None) -> str: - """Pretty print a Python list to a string.""" - if not obj: - return indent + "[]" - result = [indent, "["] - indent2 = indent + " " * 4 - # I prefer not to compress lists. - for i, obj2 in enumerate(obj): - result.append("\n" + indent2) - result.append(objToString(obj2, indent=indent2)) - if i + 1 < len(obj) > 1: - result.append(",") - else: - result.append("\n" + indent) - result.append("]") - s = "".join(result) - return f"{tag}...\n{s}\n" if tag else s - - -def tupleToString(obj: Any, indent: str = "", tag: Optional[str] = None) -> str: - """Pretty print a Python tuple to a string.""" - if not obj: - return "()," - result = ["("] - indent2 = indent + " " * 4 - for i, obj2 in enumerate(obj): - if len(obj) > 1: - result.append("\n" + indent2) - result.append(objToString(obj2, indent=indent2)) - if len(obj) == 1 or i + 1 < len(obj): - result.append(",") - elif len(obj) > 1: - result.append("\n" + indent) - result.append(")") - s = "".join(result) - return f"{tag}...\n{s}\n" if tag else s - - -def shortFileName(fileName: str, n: int = None) -> str: - """Return the base name of a path.""" - if n is not None: - trace('"n" keyword argument is no longer used') - return os.path.basename(fileName) if fileName else "" - - -shortFilename = shortFileName - - -def splitLines(s: str) -> List[str]: - """ - Split s into lines, preserving the number of lines and - the endings of all lines, including the last line. - """ - return s.splitlines(True) if s else [] # This is a Python string function! - - -splitlines = splitLines - - -def trace(*args: Any) -> None: - """Print the name of the calling function followed by all the args.""" - name = _callerName(2) - if name.endswith(".pyc"): - name = name[:-1] - args2 = "".join(str(z) for z in args) - print(f"{name} {args2}") diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index e277ac2fa..d260122cd 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -11,9 +11,6 @@ def setUp(self): Init self.project to a new Project instance for this test, with default prefs. self.project.fscommands manages temp files in a temp directory. """ - if 0: # trace: Do this before calling super().setUp() - print('\n') - print('ObjectInferTest.setUp\n') super().setUp() self.project = testutils.sample_project() @@ -28,12 +25,11 @@ class Sample(object): pass a_var = Sample() """) - scope = libutils.get_string_scope(self.project, code) - sample_scope = scope["Sample"] - sample_class = sample_scope.get_object() + sample_class = scope["Sample"].get_object() a_var = scope["a_var"].get_object() self.assertEqual(sample_class, a_var.get_type()) + def test_simple_type_inferencing_classes_defined_in_holding_scope(self): code = dedent("""\ class Sample(object): From 4228055b9befd4f4d029e553e58696b2debd3439 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 21:31:36 -0600 Subject: [PATCH 84/99] Move definition of `visitor_class` to a better spot --- rope/base/pyobjects.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 087d52f65..323a5a314 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -185,8 +185,6 @@ def absolute_name(self): obj_name = self.get_name() return self.get_module().get_name() + ("::" + obj_name if obj_name else "") - visitor_class = None - @utils.prevent_recursion(lambda: {}) def _get_structural_attributes(self): if self.structural_attributes is None: @@ -239,6 +237,8 @@ def _get_defined_objects(self): self._get_structural_attributes() return self.defineds + visitor_class = None + def _create_structural_attributes(self): if self.visitor_class is None: return {} From 09da2acb9274514590bfe382631c88736901b690 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Fri, 10 Feb 2023 23:31:18 -0600 Subject: [PATCH 85/99] Add a trace to one test --- ropetest/objectinfertest.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index d260122cd..2633a1be9 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -28,6 +28,11 @@ class Sample(object): scope = libutils.get_string_scope(self.project, code) sample_class = scope["Sample"].get_object() a_var = scope["a_var"].get_object() + if 1: # trace: + print('') + print(scope) + print(sample_class) + print(a_var) self.assertEqual(sample_class, a_var.get_type()) def test_simple_type_inferencing_classes_defined_in_holding_scope(self): From 8fb90fa9ded0a7325c245bf4f3e5e15ecd9f5842 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sat, 11 Feb 2023 05:38:27 -0600 Subject: [PATCH 86/99] Annotate all methods of class AbstractModule --- rope/base/pyobjects.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 323a5a314..f9eaa4c7c 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -1,7 +1,11 @@ -from typing import Optional +from __future__ import annotations +from typing import Optional, TYPE_CHECKING from rope.base import ast, exceptions, utils +if TYPE_CHECKING: + from rope.base.resources import Resource + class PyObject: def __init__(self, type_): @@ -149,14 +153,16 @@ def get_returned_object(self, args): class AbstractModule(PyObject): - def __init__(self, doc=None): + def __init__(self, doc=None) -> None: super().__init__(get_base_type("Module")) - def get_doc(self): - pass + def get_doc(self) -> Optional[str]: + return None - def get_resource(self): - pass + def get_name(self) -> Optional[str]: + return None + def get_resource(self) -> Optional[Resource]: + return None class PyDefinedObject: @@ -300,9 +306,8 @@ def __init__(self, pycore, ast_node, resource): PyDefinedObject.__init__(self, pycore, ast_node, None) @property - def absolute_name(self) -> str: - # mypy error? - return self.get_name() # type:ignore + def absolute_name(self) -> Optional[str]: + return self.get_name() def _get_concluded_data(self): new_data = _ConcludedData() From d9b799001c4b5772234140cbe711b7f9c7f302cb Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sat, 11 Feb 2023 05:39:37 -0600 Subject: [PATCH 87/99] blacken --- rope/base/pyobjects.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index f9eaa4c7c..88ea61b90 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -161,6 +161,7 @@ def get_doc(self) -> Optional[str]: def get_name(self) -> Optional[str]: return None + def get_resource(self) -> Optional[Resource]: return None From bb4df67b34251c9515bfe95d8565fc418bf4d4d1 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sat, 11 Feb 2023 07:17:23 -0600 Subject: [PATCH 88/99] Add PyObject.get_module --- rope/base/pyobjects.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 88ea61b90..80e3b74cf 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -23,6 +23,9 @@ def get_attribute(self, name): raise exceptions.AttributeNotFoundError("Attribute %s not found" % name) return self.get_attributes()[name] + def get_module(self) -> Optional[PyObject]: + return None + def get_type(self): return self.type From 24f82c13e4ec03dcf2d2f42c3d46e49e1644855c Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sat, 11 Feb 2023 07:53:43 -0600 Subject: [PATCH 89/99] For now, annotate all get_module functions/methods as returning Any --- rope/base/arguments.py | 5 ++--- rope/base/builtins.py | 11 ++++++++--- rope/base/oi/type_hinting/utils.py | 13 +++++++------ rope/base/project.py | 4 ++-- rope/base/pycore.py | 4 ++-- rope/base/pyobjects.py | 18 ++++++++++++++---- rope/base/pyobjectsdef.py | 5 +++-- 7 files changed, 38 insertions(+), 22 deletions(-) diff --git a/rope/base/arguments.py b/rope/base/arguments.py index d2ea58fc5..68004d91d 100644 --- a/rope/base/arguments.py +++ b/rope/base/arguments.py @@ -51,13 +51,12 @@ def _evaluate(self, ast_node): return rope.base.evaluate.eval_node(self.scope, ast_node) -# Call(expr func, expr* args, keyword* keywords) - - def create_arguments( primary, pyfunction: PyFunc, call_node: ast.Call, scope: Scope ) -> Arguments: """A factory for creating `Arguments`""" + # Call(expr func, expr* args, keyword* keywords) + args = list(call_node.args) args.extend(call_node.keywords) # type:ignore called = call_node.func diff --git a/rope/base/builtins.py b/rope/base/builtins.py index 151c64742..1053333fa 100644 --- a/rope/base/builtins.py +++ b/rope/base/builtins.py @@ -1,10 +1,15 @@ """This module tries to support builtin types and functions.""" +from __future__ import annotations import inspect import io +from typing import Any, TYPE_CHECKING import rope.base.evaluate from rope.base import arguments, ast, pynames, pyobjects, utils +if TYPE_CHECKING: + from rope.base.pyscopes import Scope + class BuiltinModule(pyobjects.AbstractModule): def __init__(self, name, pycore=None, initial={}): @@ -80,7 +85,7 @@ def get_attributes(self): result.update(self.initial) return result - def get_module(self): + def get_module(self) -> Any: return builtins @@ -695,10 +700,10 @@ def get_returned_object(self, args): else: return pyobjects.get_unknown() - def get_module(self): + def get_module(self) -> Any: return self.parent.get_module() - def get_scope(self): + def get_scope(self) -> Scope: return self.scope def get_kind(self): diff --git a/rope/base/oi/type_hinting/utils.py b/rope/base/oi/type_hinting/utils.py index add35c8e0..23c52695e 100644 --- a/rope/base/oi/type_hinting/utils.py +++ b/rope/base/oi/type_hinting/utils.py @@ -1,11 +1,14 @@ -# from __future__ import annotations +from __future__ import annotations import logging -from typing import Optional +from typing import Optional, Union, TYPE_CHECKING import rope.base.utils as base_utils from rope.base import evaluate from rope.base.exceptions import AttributeNotFoundError -from rope.base.pyobjects import PyClass, PyDefinedObject, PyFunction +from rope.base.pyobjects import PyClass, PyDefinedObject, PyFunction, PyObject + +if TYPE_CHECKING: + PyObj = Union[PyDefinedObject, PyObject] def get_super_func(pyfunc): @@ -73,9 +76,7 @@ def get_mro(pyclass): return class_list -def resolve_type( - type_name: str, pyobject: PyDefinedObject -) -> Optional[PyDefinedObject]: +def resolve_type(type_name: str, pyobject: PyObj) -> Optional[PyObj]: """ Find proper type object from its name. """ diff --git a/rope/base/project.py b/rope/base/project.py index ae104ade0..0607e1d55 100644 --- a/rope/base/project.py +++ b/rope/base/project.py @@ -1,8 +1,8 @@ -# type:ignore import contextlib import json import os import sys +from typing import Any import warnings from contextlib import ExitStack from typing import Optional @@ -54,7 +54,7 @@ def get_resource(self, resource_name): else: raise exceptions.ResourceNotFoundError("Unknown resource " + resource_name) - def get_module(self, name, folder=None): + def get_module(self, name, folder=None) -> Any: """Returns a `PyObject` if the module was found.""" # check if this is a builtin module pymod = self.pycore.builtin_module(name) diff --git a/rope/base/pycore.py b/rope/base/pycore.py index 1f5b46fe0..8330a10bf 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -2,7 +2,7 @@ import bisect import contextlib import difflib -from typing import Callable, TYPE_CHECKING +from typing import Any, Callable, TYPE_CHECKING import warnings import rope.base.libutils @@ -71,7 +71,7 @@ def is_python_file(self, resource): return self.python_matcher.does_match(resource) @utils.deprecated("Use `project.get_module` instead") - def get_module(self, name, folder=None): + def get_module(self, name, folder=None) -> Any: """Returns a `PyObject` if the module was found.""" return self.project.get_module(name, folder) diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index 80e3b74cf..d9099b263 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -1,10 +1,11 @@ from __future__ import annotations -from typing import Optional, TYPE_CHECKING +from typing import Any, Optional, TYPE_CHECKING from rope.base import ast, exceptions, utils if TYPE_CHECKING: from rope.base.resources import Resource + from rope.base.pyscopes import Scope class PyObject: @@ -23,7 +24,16 @@ def get_attribute(self, name): raise exceptions.AttributeNotFoundError("Attribute %s not found" % name) return self.get_attributes()[name] - def get_module(self) -> Optional[PyObject]: + def get_doc(self) -> Optional[str]: + return None + + def get_module(self) -> Any: + return None + + def get_name(self) -> Optional[str]: + return None + + def get_resource(self) -> Optional[Resource]: return None def get_type(self): @@ -222,12 +232,12 @@ def get_attribute(self, name): return self._get_concluded_attributes()[name] raise exceptions.AttributeNotFoundError("Attribute %s not found" % name) - def get_scope(self): + def get_scope(self) -> Scope: if self.scope is None: self.scope = self._create_scope() return self.scope - def get_module(self): + def get_module(self) -> Any: current_object = self while current_object.parent is not None: current_object = current_object.parent diff --git a/rope/base/pyobjectsdef.py b/rope/base/pyobjectsdef.py index bd91ef848..854c0d0b5 100644 --- a/rope/base/pyobjectsdef.py +++ b/rope/base/pyobjectsdef.py @@ -1,4 +1,5 @@ import ast +from typing import Any import rope.base.builtins import rope.base.codeanalyze @@ -298,7 +299,7 @@ def _get_init_dot_py(self): def _create_scope(self): return self.get_module().get_scope() - def get_module(self): + def get_module(self) -> Any: init_dot_py = self._get_init_dot_py() if init_dot_py: return self.pycore.project.get_pymodule(init_dot_py) @@ -429,7 +430,7 @@ def __init__(self, pycore, owner_object): self.names = {} self.defineds = [] - def get_module(self): + def get_module(self) -> Any: if self.owner_object is not None: return self.owner_object.get_module() else: From 863de8834ab06be21ef3992444b8a70d4e17d842 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sat, 11 Feb 2023 08:07:42 -0600 Subject: [PATCH 90/99] Fully annotate soa.py --- rope/base/oi/soa.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/rope/base/oi/soa.py b/rope/base/oi/soa.py index 648aba06d..63951a137 100644 --- a/rope/base/oi/soa.py +++ b/rope/base/oi/soa.py @@ -1,6 +1,6 @@ from __future__ import annotations import ast -from typing import Callable, List, Union, TYPE_CHECKING +from typing import Callable, List, Tuple, Union, TYPE_CHECKING import rope.base.oi.soi import rope.base.pynames @@ -12,12 +12,13 @@ from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction from rope.base.pynames import PyName + Node = ast.AST PyFunc = Union[AbstractFunction, PyFunction, DefinedPyFunction] def analyze_module( pycore, pymodule, should_analyze, search_subscopes, followed_calls: bool -): +) -> None: """Analyze `pymodule` for static object inference Analyzes scopes for collecting object information. The analysis @@ -55,19 +56,19 @@ def _follow(pyfunction: DefinedPyFunction) -> None: class SOAVisitor(rope.base.ast.RopeNodeVisitor): - def __init__(self, pycore, pydefined, follow_callback=None): + def __init__(self, pycore, pydefined, follow_callback=None) -> None: self.pycore = pycore self.pymodule = pydefined.get_module() self.scope = pydefined.get_scope() self.follow = follow_callback - def _FunctionDef(self, node): + def _FunctionDef(self, node) -> None: pass - def _ClassDef(self, node): + def _ClassDef(self, node) -> None: pass - def _Call(self, node: ast.Call): + def _Call(self, node: ast.Call) -> None: for child in ast.iter_child_nodes(node): self.visit(child) primary, pyname = evaluate.eval_node2(self.scope, node.func) @@ -121,7 +122,7 @@ def _parameter_objects(self, pyfunction: DefinedPyFunction): for i in range(len(pyfunction.get_param_names(False))) ] - def _AnnAssign(self, node): + def _AnnAssign(self, node) -> None: for child in ast.iter_child_nodes(node): self.visit(child) visitor = _SOAAssignVisitor() @@ -132,7 +133,7 @@ def _AnnAssign(self, node): self._evaluate_assign_value(node, nodes, type_hint=node.annotation) - def _Assign(self, node): + def _Assign(self, node) -> None: for child in ast.iter_child_nodes(node): self.visit(child) visitor = _SOAAssignVisitor() @@ -168,11 +169,11 @@ def _evaluate_assign_value( class _SOAAssignVisitor(nameanalyze._NodeNameCollector): - def __init__(self): + def __init__(self) -> None: super().__init__() - self.nodes = [] + self.nodes: List[Tuple] = [] - def _added(self, node, levels): + def _added(self, node, levels) -> None: if isinstance(node, ast.Subscript) and isinstance( node.slice, (ast.Index, ast.expr) ): From 2a888989475475d3b1ec7e8ae3ff21dac48c8b9a Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 12 Feb 2023 06:07:41 -0600 Subject: [PATCH 91/99] Add disabled trace --- rope/base/arguments.py | 2 +- rope/base/oi/soi.py | 43 ++++++++++++++++++++++++++++++++++--- ropetest/objectinfertest.py | 2 +- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/rope/base/arguments.py b/rope/base/arguments.py index 68004d91d..1c82df376 100644 --- a/rope/base/arguments.py +++ b/rope/base/arguments.py @@ -87,7 +87,7 @@ def get_instance_pyname(self): class MixedArguments: - def __init__(self, pyname, arguments, scope): + def __init__(self, pyname, arguments: Arguments, scope: Scope) -> None: """`arguments` is an instance of `Arguments`""" self.pyname = pyname self.args = arguments diff --git a/rope/base/oi/soi.py b/rope/base/oi/soi.py index 2f243c954..ec402f971 100644 --- a/rope/base/oi/soi.py +++ b/rope/base/oi/soi.py @@ -12,7 +12,7 @@ if TYPE_CHECKING: import ast - from rope.base.pyobjects import PyFunction + from rope.base.pyobjects import PyFunction, PyObject from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction Node = ast.AST @@ -22,27 +22,64 @@ @_ignore_inferred -def infer_returned_object(pyfunction: PyFunc, args): - """Infer the `PyObject` this `PyFunction` returns after calling""" +def infer_returned_object(pyfunction: PyFunc, args) -> PyObject: + """Infer the return type of a function.""" + import ast ### + + trace = False + + def arg_to_string(arg): + if isinstance(arg, ast.Call): + return f"Call:{arg.func.id}" # Name.id. + if isinstance(arg, ast.Constant): + return f"Constant:{arg.value}" + if isinstance(arg, ast.Name): + return f"Name:{arg.id}" + if isinstance(arg, ast.keyword): + arg2 = getattr(arg, "arg", None) + return f"keyword:{arg2}" if arg2 else "keyword" + return arg.__class__.__name__ + + def report(kind, result): + if not trace: + return + # from rope.base.arguments import Arguments + # if isinstance(args, Arguments): breakpoint() + try: + args_s = ",".join([arg_to_string(arg) for arg in args.args]) + except AttributeError: + args_s = args.__class__.__name__ # ObjectArguments have no args member. + print("") + print( + "soi.infer_returned_object...\n" + f"{pyfunction.absolute_name:>15} args: {args_s:<20} " + f"==> {kind} {result.__class__.__name__}" + ) + object_info = pyfunction.pycore.object_info result = object_info.get_exact_returned(pyfunction, args) if result is not None: + report("Cached", result) return result result = _infer_returned(pyfunction, args) if result is not None: if args and pyfunction.get_module().get_resource() is not None: params = args.get_arguments(pyfunction.get_param_names(special_args=False)) object_info.function_called(pyfunction, params, result) + report("_infer_returned", result) return result result = object_info.get_returned(pyfunction, args) if result is not None: + report("get_returned", result) return result hint_return = get_type_hinting_factory( pyfunction.pycore.project ).make_return_provider() type_ = hint_return(pyfunction) if type_ is not None: + report("hint_returned", result) return pyobjects.PyObject(type_) + report("Fail", None) @_ignore_inferred diff --git a/ropetest/objectinfertest.py b/ropetest/objectinfertest.py index 2633a1be9..baae9ad58 100644 --- a/ropetest/objectinfertest.py +++ b/ropetest/objectinfertest.py @@ -28,7 +28,7 @@ class Sample(object): scope = libutils.get_string_scope(self.project, code) sample_class = scope["Sample"].get_object() a_var = scope["a_var"].get_object() - if 1: # trace: + if 0: # trace: print('') print(scope) print(sample_class) From 7de434a52df2ad114572bf231917ad500899da37 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 12 Feb 2023 07:24:18 -0600 Subject: [PATCH 92/99] Remove wildcard import of ast --- rope/base/arguments.py | 4 +++- rope/base/ast.py | 4 +++- rope/base/builtins.py | 3 ++- rope/base/change.py | 5 +++-- rope/base/evaluate.py | 6 ++++-- rope/base/fscommands.py | 1 - rope/base/nameanalyze.py | 7 +++++-- rope/base/oi/doa.py | 1 - rope/base/oi/soa.py | 3 ++- rope/base/oi/soi.py | 5 +++-- .../oi/type_hinting/providers/numpydocstrings.py | 4 ++-- rope/base/pyobjects.py | 3 ++- rope/base/pyscopes.py | 3 ++- rope/contrib/autoimport/parse.py | 3 ++- rope/contrib/finderrors.py | 6 ++++-- rope/contrib/generate.py | 2 +- rope/refactor/extract.py | 15 ++++++++------- rope/refactor/importutils/module_imports.py | 6 ++++-- rope/refactor/move.py | 2 +- rope/refactor/occurrences.py | 9 +++++---- rope/refactor/patchedast.py | 3 ++- rope/refactor/restructure.py | 3 ++- rope/refactor/similarfinder.py | 6 ++++-- rope/refactor/suites.py | 5 +++-- rope/refactor/usefunction.py | 6 ++++-- rope/refactor/wildcards.py | 4 +++- ropetest/refactor/patchedasttest.py | 11 ++++++----- 27 files changed, 80 insertions(+), 50 deletions(-) diff --git a/rope/base/arguments.py b/rope/base/arguments.py index 1c82df376..622445b2a 100644 --- a/rope/base/arguments.py +++ b/rope/base/arguments.py @@ -1,7 +1,9 @@ from __future__ import annotations +import ast from typing import Any, Union, TYPE_CHECKING import rope.base.evaluate -from rope.base import ast + +# from rope.base import ast if TYPE_CHECKING: from rope.base.pyobjects import AbstractFunction, PyFunction diff --git a/rope/base/ast.py b/rope/base/ast.py index fcb5996b6..9475c22dd 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -1,9 +1,11 @@ import ast import sys -from ast import * # noqa: F401,F403 + +# from ast import * # noqa: F401,F403 from rope.base import fscommands +# Handle Python 3.7 and before. try: from ast import _const_node_type_names # type:ignore except ImportError: diff --git a/rope/base/builtins.py b/rope/base/builtins.py index 1053333fa..3cd156f63 100644 --- a/rope/base/builtins.py +++ b/rope/base/builtins.py @@ -1,11 +1,12 @@ """This module tries to support builtin types and functions.""" from __future__ import annotations +import ast import inspect import io from typing import Any, TYPE_CHECKING import rope.base.evaluate -from rope.base import arguments, ast, pynames, pyobjects, utils +from rope.base import arguments, pynames, pyobjects, utils if TYPE_CHECKING: from rope.base.pyscopes import Scope diff --git a/rope/base/change.py b/rope/base/change.py index 38173fc46..cf59b279b 100644 --- a/rope/base/change.py +++ b/rope/base/change.py @@ -6,7 +6,8 @@ import rope.base.fscommands from rope.base import exceptions, taskhandle, utils -from rope.base.fscommands import FileContent # type:ignore + +from rope.base.fscommands import FileContent class Change: @@ -334,7 +335,7 @@ def _get_fscommands(self, resource): def write_file(self, resource, contents: Union[str, FileContent]): data: FileContent if not isinstance(contents, bytes): - data = rope.base.fscommands.unicode_to_file_data( # type:ignore + data = rope.base.fscommands.unicode_to_file_data( contents, newlines=resource.newlines, ) diff --git a/rope/base/evaluate.py b/rope/base/evaluate.py index aa07cfa9f..97789f540 100644 --- a/rope/base/evaluate.py +++ b/rope/base/evaluate.py @@ -1,4 +1,5 @@ from __future__ import annotations +import ast from operator import itemgetter from typing import Optional, Tuple, TYPE_CHECKING @@ -7,13 +8,14 @@ import rope.base.pyobjects from rope.base import ( arguments, - ast, + # ast, exceptions, nameanalyze, pyobjects, pyobjectsdef, worder, ) +from rope.base.ast import RopeNodeVisitor if TYPE_CHECKING: from rope.base.pyscopes import Scope @@ -161,7 +163,7 @@ def _find_module(self, module_name): ) -class StatementEvaluator(ast.RopeNodeVisitor): +class StatementEvaluator(rope.base.ast.RopeNodeVisitor): def __init__(self, scope: Scope): self.scope = scope self.result = None diff --git a/rope/base/fscommands.py b/rope/base/fscommands.py index aa79f2cb0..00ba71c8a 100644 --- a/rope/base/fscommands.py +++ b/rope/base/fscommands.py @@ -1,4 +1,3 @@ -# type:ignore """Project file system commands. This modules implements file system operations used by rope. Different diff --git a/rope/base/nameanalyze.py b/rope/base/nameanalyze.py index e98a4ac7b..5e151e72b 100644 --- a/rope/base/nameanalyze.py +++ b/rope/base/nameanalyze.py @@ -1,5 +1,8 @@ +import ast from typing import List -from rope.base import ast + +from rope.base.ast import RopeNodeVisitor +# from rope.base import ast def get_name_levels(node): @@ -19,7 +22,7 @@ def get_name_levels(node): return visitor.names -class _NodeNameCollector(ast.RopeNodeVisitor): +class _NodeNameCollector(RopeNodeVisitor): def __init__(self, levels: List[int] = None): self.names: List[str] = [] self.levels = levels diff --git a/rope/base/oi/doa.py b/rope/base/oi/doa.py index b6d761a91..82958ce3d 100644 --- a/rope/base/oi/doa.py +++ b/rope/base/oi/doa.py @@ -1,4 +1,3 @@ -# type:ignore import base64 import contextlib import hashlib diff --git a/rope/base/oi/soa.py b/rope/base/oi/soa.py index 63951a137..2d20bb270 100644 --- a/rope/base/oi/soa.py +++ b/rope/base/oi/soa.py @@ -5,6 +5,7 @@ import rope.base.oi.soi import rope.base.pynames from rope.base import arguments, evaluate, nameanalyze, pyobjects +from rope.base.ast import RopeNodeVisitor if TYPE_CHECKING: from rope.base.pycore import PyCore @@ -55,7 +56,7 @@ def _follow(pyfunction: DefinedPyFunction) -> None: visitor.visit(child) -class SOAVisitor(rope.base.ast.RopeNodeVisitor): +class SOAVisitor(RopeNodeVisitor): def __init__(self, pycore, pydefined, follow_callback=None) -> None: self.pycore = pycore self.pymodule = pydefined.get_module() diff --git a/rope/base/oi/soi.py b/rope/base/oi/soi.py index ec402f971..19dc4cfd5 100644 --- a/rope/base/oi/soi.py +++ b/rope/base/oi/soi.py @@ -5,7 +5,7 @@ """ from __future__ import annotations -from typing import Any, Union, TYPE_CHECKING +from typing import Any, Optional, Union, TYPE_CHECKING import rope.base.builtins # Use full qualification for clarity. from rope.base import arguments, evaluate, pynames, pyobjects, utils from rope.base.oi.type_hinting.factory import get_type_hinting_factory @@ -22,7 +22,7 @@ @_ignore_inferred -def infer_returned_object(pyfunction: PyFunc, args) -> PyObject: +def infer_returned_object(pyfunction: PyFunc, args) -> Optional[PyObject]: """Infer the return type of a function.""" import ast ### @@ -80,6 +80,7 @@ def report(kind, result): report("hint_returned", result) return pyobjects.PyObject(type_) report("Fail", None) + return None @_ignore_inferred diff --git a/rope/base/oi/type_hinting/providers/numpydocstrings.py b/rope/base/oi/type_hinting/providers/numpydocstrings.py index ea989920c..fa1f671d3 100644 --- a/rope/base/oi/type_hinting/providers/numpydocstrings.py +++ b/rope/base/oi/type_hinting/providers/numpydocstrings.py @@ -1,12 +1,12 @@ -# type: ignore """ Some code extracted (or based on code) from: https://github.com/davidhalter/jedi/blob/b489019f5bd5750051122b94cc767df47751ecb7/jedi/evaluate/docstrings.py Thanks to @davidhalter for this utils under MIT License. """ +import ast import re -from rope.base.ast import literal_eval +# from rope.base.ast import literal_eval from rope.base.oi.type_hinting.providers import docstrings # type:ignore try: diff --git a/rope/base/pyobjects.py b/rope/base/pyobjects.py index d9099b263..312b92dd9 100644 --- a/rope/base/pyobjects.py +++ b/rope/base/pyobjects.py @@ -1,7 +1,8 @@ from __future__ import annotations +import ast from typing import Any, Optional, TYPE_CHECKING -from rope.base import ast, exceptions, utils +from rope.base import exceptions, utils if TYPE_CHECKING: from rope.base.resources import Resource diff --git a/rope/base/pyscopes.py b/rope/base/pyscopes.py index 565541903..d979e0dff 100644 --- a/rope/base/pyscopes.py +++ b/rope/base/pyscopes.py @@ -1,5 +1,6 @@ +import ast import rope.base.builtins # Use full qualification for clarity. -from rope.base import ast, codeanalyze, exceptions, pynames, utils +from rope.base import codeanalyze, exceptions, pynames, utils from rope.refactor import patchedast diff --git a/rope/contrib/autoimport/parse.py b/rope/contrib/autoimport/parse.py index 58ee8fcbd..4fc422a95 100644 --- a/rope/contrib/autoimport/parse.py +++ b/rope/contrib/autoimport/parse.py @@ -10,7 +10,8 @@ from importlib import import_module from typing import Generator, List -from rope.base import ast +# from rope.base import ast +import ast from .defs import ( ModuleCompiled, diff --git a/rope/contrib/finderrors.py b/rope/contrib/finderrors.py index 4022b2d6c..ce03d0888 100644 --- a/rope/contrib/finderrors.py +++ b/rope/contrib/finderrors.py @@ -24,7 +24,9 @@ """ from typing import List -from rope.base import ast, evaluate, pyobjects +import ast +from rope.base import evaluate, pyobjects +from rope.base.ast import RopeNodeVisitor from rope.base.pyobjects import PyModule from rope.base.pyscopes import Scope @@ -40,7 +42,7 @@ def find_errors(project, resource): return finder.errors -class _BadAccessFinder(ast.RopeNodeVisitor): +class _BadAccessFinder(RopeNodeVisitor): def __init__(self, pymodule: PyModule): self.pymodule = pymodule self.scope: Scope = pymodule.get_scope() diff --git a/rope/contrib/generate.py b/rope/contrib/generate.py index e535b1ec6..2e6c81b49 100644 --- a/rope/contrib/generate.py +++ b/rope/contrib/generate.py @@ -17,7 +17,7 @@ if TYPE_CHECKING: from typing import Literal, Optional - from rope.base.project import Project # type:ignore + from rope.base.project import Project from rope.base.resources import Resource GenerateKind = Literal[ diff --git a/rope/refactor/extract.py b/rope/refactor/extract.py index f57c4e7d1..452d576e4 100644 --- a/rope/refactor/extract.py +++ b/rope/refactor/extract.py @@ -1,10 +1,11 @@ import re -from typing import Dict +import ast from contextlib import contextmanager from itertools import chain from typing import Dict -from rope.base import ast, codeanalyze +from rope.base import codeanalyze +from rope.base.ast import RopeNodeVisitor from rope.base.change import ChangeContents, ChangeSet from rope.base.exceptions import RefactoringError from rope.base.utils.datastructures import OrderedSet @@ -515,7 +516,7 @@ def _is_on_a_word(self, info, offset): return next.isalnum() or next == "_" -class _ExtractMethodParts(ast.RopeNodeVisitor): +class _ExtractMethodParts(RopeNodeVisitor): def __init__(self, info): self.info: str = info self.info_collector = self._create_info_collector() @@ -778,7 +779,7 @@ def get_checks(self): return {} -class _FunctionInformationCollector(ast.RopeNodeVisitor): +class _FunctionInformationCollector(RopeNodeVisitor): def __init__(self, start: int, end: int, is_global: bool): self.start = start self.end = end @@ -959,7 +960,7 @@ def _get_argnames(arguments): return result -class _VariableReadsAndWritesFinder(ast.RopeNodeVisitor): +class _VariableReadsAndWritesFinder(RopeNodeVisitor): def __init__(self): self.written = set() self.read = set() @@ -999,7 +1000,7 @@ def find_reads_for_one_liners(code): return visitor.read -class _BaseErrorFinder(ast.RopeNodeVisitor): +class _BaseErrorFinder(RopeNodeVisitor): @classmethod def has_errors(cls, code): if code.strip() == "": @@ -1067,7 +1068,7 @@ def _ClassDef(self, node): pass -class _GlobalFinder(ast.RopeNodeVisitor): +class _GlobalFinder(RopeNodeVisitor): def __init__(self): self.globals_ = OrderedSet() diff --git a/rope/refactor/importutils/module_imports.py b/rope/refactor/importutils/module_imports.py index b1dd5463d..2bb6cb301 100644 --- a/rope/refactor/importutils/module_imports.py +++ b/rope/refactor/importutils/module_imports.py @@ -1,7 +1,9 @@ from __future__ import annotations +import ast from typing import Callable, List, Set, Union, TYPE_CHECKING -from rope.base import ast, exceptions, pynames, pynamesdef, utils +from rope.base import exceptions, pynames, pynamesdef, utils +from rope.base.ast import RopeNodeVisitor from rope.refactor.importutils import actions, importinfo if TYPE_CHECKING: @@ -421,7 +423,7 @@ def _can_name_be_added(self, imported_primary): return False -class _UnboundNameFinder(ast.RopeNodeVisitor): +class _UnboundNameFinder(RopeNodeVisitor): def __init__(self, pyobject: PyObject): self.pyobject = pyobject diff --git a/rope/refactor/move.py b/rope/refactor/move.py index e5334b96d..c77349774 100644 --- a/rope/refactor/move.py +++ b/rope/refactor/move.py @@ -1,4 +1,3 @@ -# type:ignore """A module containing classes for move refactoring `create_move()` is a factory for creating move refactoring objects @@ -331,6 +330,7 @@ def get_changes( resources = self.project.get_python_files() if dest is None or not dest.exists(): raise exceptions.RefactoringError("Move destination does not exist.") + ### Valid pylint complaints ... if dest.is_folder() and dest.has_child("__init__.py"): # type:ignore dest = dest.get_child("__init__.py") # type:ignore if dest.is_folder(): # type:ignore diff --git a/rope/refactor/occurrences.py b/rope/refactor/occurrences.py index 89ffdcd91..579e02016 100644 --- a/rope/refactor/occurrences.py +++ b/rope/refactor/occurrences.py @@ -34,13 +34,13 @@ * `keywords`: If False, don't return instances that are the names of keyword arguments """ - +import ast import contextlib import re from rope.base import ( - ast, + # ast, codeanalyze, evaluate, exceptions, @@ -49,6 +49,7 @@ utils, worder, ) +import rope.base.ast as rast class Finder: @@ -339,8 +340,8 @@ def _re_search(self, source): yield match.start("fstring") + occurrence_node.col_offset def _search_in_f_string(self, f_string): - tree = ast.parse(f_string) - for node in ast.walk(tree): + tree = rast.parse(f_string) + for node in rast.ast.walk(tree): if isinstance(node, ast.Name) and node.id == self.name: yield node diff --git a/rope/refactor/patchedast.py b/rope/refactor/patchedast.py index 06f185005..473b43e9b 100644 --- a/rope/refactor/patchedast.py +++ b/rope/refactor/patchedast.py @@ -1,10 +1,11 @@ +import ast import collections import numbers import re import warnings from itertools import chain -from rope.base import ast, codeanalyze, exceptions +from rope.base import codeanalyze, exceptions COMMA_IN_WITH_PATTERN = re.compile(r"\(.*?\)|(,)") diff --git a/rope/refactor/restructure.py b/rope/refactor/restructure.py index 55a4b2d03..a021fa5f6 100644 --- a/rope/refactor/restructure.py +++ b/rope/refactor/restructure.py @@ -1,6 +1,7 @@ +import ast import warnings -from rope.base import ast, builtins, change, codeanalyze, libutils, taskhandle +from rope.base import builtins, change, codeanalyze, libutils, taskhandle from rope.refactor import patchedast, similarfinder, sourceutils from rope.refactor.importutils import module_imports diff --git a/rope/refactor/similarfinder.py b/rope/refactor/similarfinder.py index 6d2d2e1bc..b584e317a 100644 --- a/rope/refactor/similarfinder.py +++ b/rope/refactor/similarfinder.py @@ -1,9 +1,11 @@ """This module can be used for finding similar code""" +import ast import re import rope.base.builtins # Use full qualification for clarity. import rope.refactor.wildcards # Use full qualification for clarity. -from rope.base import ast, codeanalyze, exceptions, libutils +from rope.base import codeanalyze, exceptions, libutils +# from rope.base.ast import RopeNodeVisitor from rope.refactor import patchedast from rope.refactor.patchedast import MismatchedTokenError @@ -155,7 +157,7 @@ def find_matches(self): self.matches = [] # _check_nodes always returns None, so # call_for_nodes traverses self.body's entire tree. - ast.call_for_nodes(self.body, self._check_node) + rope.base.ast.call_for_nodes(self.body, self._check_node) return self.matches def _check_node(self, node): diff --git a/rope/refactor/suites.py b/rope/refactor/suites.py index 133652b20..a4d9b387f 100644 --- a/rope/refactor/suites.py +++ b/rope/refactor/suites.py @@ -1,6 +1,7 @@ +import ast from itertools import chain -from rope.base import ast +from rope.base.ast import RopeNodeVisitor def find_visible(node, lines): @@ -98,7 +99,7 @@ def _get_level(self): return self.parent._get_level() + 1 -class _SuiteWalker(ast.RopeNodeVisitor): +class _SuiteWalker(RopeNodeVisitor): def __init__(self, suite): self.suite = suite self.suites = [] diff --git a/rope/refactor/usefunction.py b/rope/refactor/usefunction.py index cf1330e80..0e9e92693 100644 --- a/rope/refactor/usefunction.py +++ b/rope/refactor/usefunction.py @@ -1,5 +1,6 @@ +import ast from rope.base import ( - ast, + # ast, change, evaluate, exceptions, @@ -8,6 +9,7 @@ pyobjects, taskhandle, ) +from rope.base.ast import RopeNodeVisitor from rope.refactor import restructure, similarfinder, sourceutils @@ -181,7 +183,7 @@ def _named_expr_count(node): return visitor.named_expression -class _ReturnOrYieldFinder(ast.RopeNodeVisitor): +class _ReturnOrYieldFinder(RopeNodeVisitor): def __init__(self): self.returns = 0 self.named_expression = 0 diff --git a/rope/refactor/wildcards.py b/rope/refactor/wildcards.py index 13edab91c..d0c108902 100644 --- a/rope/refactor/wildcards.py +++ b/rope/refactor/wildcards.py @@ -1,4 +1,6 @@ -from rope.base import ast, builtins, evaluate, pyobjects +import ast + +from rope.base import builtins, evaluate, pyobjects from rope.refactor import occurrences, patchedast diff --git a/ropetest/refactor/patchedasttest.py b/ropetest/refactor/patchedasttest.py index 0b4ca1a67..e8494ca8f 100644 --- a/ropetest/refactor/patchedasttest.py +++ b/ropetest/refactor/patchedasttest.py @@ -1,9 +1,10 @@ +import ast import itertools import sys import unittest from textwrap import dedent -from rope.base import ast +import rope.base.ast as rast from rope.refactor import patchedast from ropetest import testutils @@ -1532,13 +1533,13 @@ def __call__(self, node): if str(node).startswith(text): self.result = node break - if ast.get_node_type_name(node).startswith(text): + if rast.get_node_type_name(node).startswith(text): self.result = node break return self.result is not None search = Search() - ast.call_for_nodes(self.ast, search) + rast.call_for_nodes(self.ast, search) return search.result def check_children(self, text, children): @@ -1558,7 +1559,7 @@ def check_children(self, text, children): else: self.test_case.assertNotEqual("", text, "probably ignoring some node") self.test_case.assertTrue( - ast.get_node_type_name(child).startswith(expected), + rast.get_node_type_name(child).startswith(expected), msg="Expected <%s> but was <%s>" - % (expected, ast.get_node_type_name(child)), + % (expected, rast.get_node_type_name(child)), ) From 42d3105494d61d79c973bf6623ed9c4e4a9f9985 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 12 Feb 2023 07:44:41 -0600 Subject: [PATCH 93/99] Remove `# type:ignore` commants and fix a few mypy complaints --- rope/base/arguments.py | 8 +++----- rope/base/ast.py | 4 +--- rope/base/nameanalyze.py | 1 + rope/base/oi/type_hinting/evaluate.py | 2 ++ rope/base/oi/type_hinting/providers/numpydocstrings.py | 7 +++++-- rope/base/prefs.py | 1 + rope/base/pycore.py | 2 +- rope/contrib/autoimport/sqlite.py | 6 +++++- rope/refactor/importutils/module_imports.py | 3 +++ rope/refactor/move.py | 6 +++++- rope/refactor/similarfinder.py | 1 + 11 files changed, 28 insertions(+), 13 deletions(-) diff --git a/rope/base/arguments.py b/rope/base/arguments.py index 622445b2a..f61a5539c 100644 --- a/rope/base/arguments.py +++ b/rope/base/arguments.py @@ -1,10 +1,8 @@ from __future__ import annotations import ast -from typing import Any, Union, TYPE_CHECKING +from typing import Any, List, Union, TYPE_CHECKING import rope.base.evaluate -# from rope.base import ast - if TYPE_CHECKING: from rope.base.pyobjects import AbstractFunction, PyFunction from rope.base.pyobjectsdef import PyFunction as DefinedPyFunction @@ -59,8 +57,8 @@ def create_arguments( """A factory for creating `Arguments`""" # Call(expr func, expr* args, keyword* keywords) - args = list(call_node.args) - args.extend(call_node.keywords) # type:ignore + args: List = list(call_node.args) + args.extend(call_node.keywords) called = call_node.func # XXX: Handle constructors if _is_method_call(primary, pyfunction) and isinstance(called, ast.Attribute): diff --git a/rope/base/ast.py b/rope/base/ast.py index 9475c22dd..30e61a0ca 100644 --- a/rope/base/ast.py +++ b/rope/base/ast.py @@ -1,8 +1,6 @@ import ast import sys -# from ast import * # noqa: F401,F403 - from rope.base import fscommands # Handle Python 3.7 and before. @@ -23,7 +21,7 @@ } -def parse(source, filename="", *args, **kwargs): # type: ignore +def parse(source, filename="", *args, **kwargs): if isinstance(source, str): source = fscommands.unicode_to_file_data(source) if b"\r" in source: diff --git a/rope/base/nameanalyze.py b/rope/base/nameanalyze.py index 5e151e72b..299f8ad97 100644 --- a/rope/base/nameanalyze.py +++ b/rope/base/nameanalyze.py @@ -2,6 +2,7 @@ from typing import List from rope.base.ast import RopeNodeVisitor + # from rope.base import ast diff --git a/rope/base/oi/type_hinting/evaluate.py b/rope/base/oi/type_hinting/evaluate.py index e3fa9f4c5..ebe1e42e5 100644 --- a/rope/base/oi/type_hinting/evaluate.py +++ b/rope/base/oi/type_hinting/evaluate.py @@ -1,4 +1,6 @@ +# mypy reports various problems. # type:ignore + # Based on super lightweight Simple Top-Down Parser from http://effbot.org/zone/simple-top-down-parsing.htm # and https://bitbucket.org/emacsway/sqlbuilder/src/default/sqlbuilder/smartsql/contrib/evaluate.py import re diff --git a/rope/base/oi/type_hinting/providers/numpydocstrings.py b/rope/base/oi/type_hinting/providers/numpydocstrings.py index fa1f671d3..6abe91455 100644 --- a/rope/base/oi/type_hinting/providers/numpydocstrings.py +++ b/rope/base/oi/type_hinting/providers/numpydocstrings.py @@ -6,10 +6,10 @@ import ast import re -# from rope.base.ast import literal_eval -from rope.base.oi.type_hinting.providers import docstrings # type:ignore +from rope.base.oi.type_hinting.providers import docstrings try: + # mypy: Cannot find implementation or library stub for module named "numpydoc.docscrape" from numpydoc.docscrape import NumpyDocString # type:ignore except ImportError: NumpyDocString = None @@ -41,4 +41,7 @@ def __call__(self, docstring, param_name): if not NumpyDocString: + # mypy: Cannot assign to a type + # mypy: Incompatible types in assignment (expression has type "Type[_DummyParamParser]", + # variable has type "Type[NumPyDocstringParamParser]") NumPyDocstringParamParser = _DummyParamParser # type:ignore diff --git a/rope/base/prefs.py b/rope/base/prefs.py index cf7013b92..9d4fd4a43 100644 --- a/rope/base/prefs.py +++ b/rope/base/prefs.py @@ -1,3 +1,4 @@ +# mypy reports many problems. # type: ignore """Rope preferences.""" from dataclasses import asdict, dataclass diff --git a/rope/base/pycore.py b/rope/base/pycore.py index 8330a10bf..1240018d3 100644 --- a/rope/base/pycore.py +++ b/rope/base/pycore.py @@ -211,7 +211,7 @@ def analyze_module( followed_calls = self.project.prefs.get("soa_followed_calls", 0) pymodule = self.resource_to_pyobject(resource) self.module_cache.forget_all_data() - rope.base.oi.soa.analyze_module( # type:ignore + rope.base.oi.soa.analyze_module( self, pymodule, should_analyze, search_subscopes, followed_calls ) diff --git a/rope/contrib/autoimport/sqlite.py b/rope/contrib/autoimport/sqlite.py index 04521ff46..16791bc88 100644 --- a/rope/contrib/autoimport/sqlite.py +++ b/rope/contrib/autoimport/sqlite.py @@ -1,4 +1,3 @@ -# type:ignore """AutoImport module for rope.""" import contextlib @@ -436,6 +435,11 @@ def filter_folders(folder: Path) -> bool: folders = self.project.get_python_path_folders() folder_paths = map(lambda folder: Path(folder.real_path), folders) + + # Valid mypy complaint: + # error: Incompatible types in assignment + # (expression has type "filter[Path]", variable has type "map[Path]") + folder_paths = filter(filter_folders, folder_paths) # type:ignore return list(OrderedDict.fromkeys(folder_paths)) diff --git a/rope/refactor/importutils/module_imports.py b/rope/refactor/importutils/module_imports.py index 2bb6cb301..0f05b5e13 100644 --- a/rope/refactor/importutils/module_imports.py +++ b/rope/refactor/importutils/module_imports.py @@ -481,6 +481,9 @@ def __init__(self, pymodule: PyModule, wanted_pyobject: PyObject): for name, pyname in pymodule._get_structural_attributes().items(): if not isinstance(pyname, (pynames.ImportedName, pynames.ImportedModule)): self.names.add(name) + + # Valid mypy complaint: "PyObject" has no attribute "get_scope" + wanted_scope = wanted_pyobject.get_scope() # type:ignore self.start = wanted_scope.get_start() self.end = wanted_scope.get_end() + 1 diff --git a/rope/refactor/move.py b/rope/refactor/move.py index c77349774..b36967d44 100644 --- a/rope/refactor/move.py +++ b/rope/refactor/move.py @@ -330,7 +330,11 @@ def get_changes( resources = self.project.get_python_files() if dest is None or not dest.exists(): raise exceptions.RefactoringError("Move destination does not exist.") - ### Valid pylint complaints ... + + # Valid pylint complaints: + # "Resource" has no attribute "has_child" + # "Resource" has no attribute "get_child" + if dest.is_folder() and dest.has_child("__init__.py"): # type:ignore dest = dest.get_child("__init__.py") # type:ignore if dest.is_folder(): # type:ignore diff --git a/rope/refactor/similarfinder.py b/rope/refactor/similarfinder.py index b584e317a..3eb4c27ce 100644 --- a/rope/refactor/similarfinder.py +++ b/rope/refactor/similarfinder.py @@ -5,6 +5,7 @@ import rope.base.builtins # Use full qualification for clarity. import rope.refactor.wildcards # Use full qualification for clarity. from rope.base import codeanalyze, exceptions, libutils + # from rope.base.ast import RopeNodeVisitor from rope.refactor import patchedast from rope.refactor.patchedast import MismatchedTokenError From 934e087c6656e8e52ac3b68313b468d6d0cf6f80 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 12 Feb 2023 07:47:58 -0600 Subject: [PATCH 94/99] Fix a valid flake8 complaint --- rope/base/oi/type_hinting/providers/numpydocstrings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rope/base/oi/type_hinting/providers/numpydocstrings.py b/rope/base/oi/type_hinting/providers/numpydocstrings.py index 6abe91455..9161f3ad7 100644 --- a/rope/base/oi/type_hinting/providers/numpydocstrings.py +++ b/rope/base/oi/type_hinting/providers/numpydocstrings.py @@ -28,7 +28,7 @@ def __call__(self, docstring, param_name): p_type = m.group(1) if p_type.startswith("{"): - types = {type(x).__name__ for x in literal_eval(p_type)} + types = {type(x).__name__ for x in ast.literal_eval(p_type)} return list(types) else: return [p_type] From fc942110a64d6d63521a66734695762c6bb48441 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 12 Feb 2023 10:58:20 -0600 Subject: [PATCH 95/99] Simplify --- rope/base/evaluate.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rope/base/evaluate.py b/rope/base/evaluate.py index 97789f540..84e0a8505 100644 --- a/rope/base/evaluate.py +++ b/rope/base/evaluate.py @@ -8,7 +8,6 @@ import rope.base.pyobjects from rope.base import ( arguments, - # ast, exceptions, nameanalyze, pyobjects, @@ -163,7 +162,7 @@ def _find_module(self, module_name): ) -class StatementEvaluator(rope.base.ast.RopeNodeVisitor): +class StatementEvaluator(RopeNodeVisitor): def __init__(self, scope: Scope): self.scope = scope self.result = None From 5065e5aee06f780c3903c4d4cfe573d72cf1dc0f Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 19 Feb 2023 19:02:12 -0600 Subject: [PATCH 96/99] Create short readme --- README-Original.rst | 113 +++++++++++++++++++++++++++++++++++++++++++ README.rst | 115 ++------------------------------------------ 2 files changed, 117 insertions(+), 111 deletions(-) create mode 100644 README-Original.rst diff --git a/README-Original.rst b/README-Original.rst new file mode 100644 index 000000000..52d229431 --- /dev/null +++ b/README-Original.rst @@ -0,0 +1,113 @@ + +.. _GitHub python-rope / rope: https://github.com/python-rope/rope + + +========================================================================= + rope -- the world's most advanced open source Python refactoring library +========================================================================= + +|Build status badge| |Latest version badge| |Download count badge| |ReadTheDocs status badge| + +.. |Build status badge| image:: https://github.com/python-rope/rope/actions/workflows/main.yml/badge.svg + :target: https://github.com/python-rope/rope/actions/workflows/main.yml + :alt: Build Status + +.. |Latest version badge| image:: https://badge.fury.io/py/rope.svg + :target: https://badge.fury.io/py/rope + :alt: Latest version + +.. |Download count badge| image:: https://img.shields.io/pypi/dm/rope.svg + :alt: Download count + +.. |ReadTheDocs status badge| image:: https://readthedocs.org/projects/rope/badge/?version=latest + :target: https://rope.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +Overview +======== + +`Rope`_ is the world's most advanced open source Python refactoring library +(yes, I totally stole that tagline from Postgres). + +.. _`rope`: https://github.com/python-rope/rope + + +Most Python syntax up to Python 3.10 is supported. Please file bugs and contribute +patches if you encounter gaps. + +Since version 1.0.0, rope no longer support running on Python 2. +If you need Python 2 support, then check out the `python2` branch or the 0.x.x +releases. + +Getting Started +=============== + +* `Documentation `_ +* `How to use Rope in my IDE or Text editor? `_ +* `Configuration `_ +* `List of features `_ +* `Overview of some of rope's features `_ +* `Using as a library `_ +* `Contributing `_ + +Why use Rope? +============= + +- Rope aims to provide powerful and safe refactoring +- Rope is light on dependency, Rope only depends on Python itself +- Unlike PyRight or PyLance, Rope does not depend on Node.js +- Unlike PyLance or PyCharm, Rope is open source. +- Unlike PyRight and PyLance, Rope is written in Python itself, so if you experience problems, you would be able to debug and hack it yourself in a language that you are already familiar with +- In comparison to Jedi, Rope is focused on refactoring. While Jedi provides some basic refactoring capabilities, Rope supports many more advanced refactoring operations and options that Jedi does not. + + +Bug Reports +=========== + +Send your bug reports and feature requests at `python-rope's issue tracker`_ in GitHub. + +.. _`python-rope's issue tracker`: https://github.com/python-rope/rope/issues + + +Maintainers +=========== + +Current active maintainer of Rope is Lie Ryan (`@lieryan`_). + +Special Thanks +============== + +Many thanks the following people: + +- Ali Gholami Rudi (`@aligrudi`_) for initially creating the initial Rope project and most of Rope's code +- Matej Cepl (`@mcepl`_) as former long-time Rope maintainer +- Nick Smith (`@soupytwist`_) as former Rope maintainer +- `all of our current and former contributors`_ +- `all authors of editor integrations`_ +- all maintainers of distro/package managers + +.. _`@aligrudi`: https://github.com/aligrudi +.. _`@soupytwist`: https://github.com/soupytwist +.. _`@lieryan`: https://github.com/lieryan +.. _`@mcepl`: https://github.com/mcepl +.. _`all of our current and former contributors`: https://github.com/python-rope/rope/blob/master/CONTRIBUTORS.md +.. _`all authors of editor integrations`: https://github.com/python-rope/rope/wiki/How-to-use-Rope-in-my-IDE-or-Text-editor%3F + +Packaging Status +================ + +.. image:: https://repology.org/badge/vertical-allrepos/python:rope.svg?exclude_unsupported=1 + :target: https://repology.org/project/python:rope/versions + :alt: Packaging status + +.. image:: https://repology.org/badge/vertical-allrepos/rope.svg?exclude_unsupported=1 + :target: https://repology.org/project/rope/versions + :alt: Packaging status + +License +======= + +This program is under the terms of LGPL v3+ (GNU Lesser General Public License). +Have a look at `COPYING`_ for more information. + +.. _`COPYING`: COPYING diff --git a/README.rst b/README.rst index 52d229431..831356408 100644 --- a/README.rst +++ b/README.rst @@ -1,113 +1,6 @@ +.. _Rope: https://github.com/python-rope/rope +.. _`original readme file`: README.rst -.. _GitHub python-rope / rope: https://github.com/python-rope/rope +A fork of `Rope`_ to develop a Theory of Operation. - -========================================================================= - rope -- the world's most advanced open source Python refactoring library -========================================================================= - -|Build status badge| |Latest version badge| |Download count badge| |ReadTheDocs status badge| - -.. |Build status badge| image:: https://github.com/python-rope/rope/actions/workflows/main.yml/badge.svg - :target: https://github.com/python-rope/rope/actions/workflows/main.yml - :alt: Build Status - -.. |Latest version badge| image:: https://badge.fury.io/py/rope.svg - :target: https://badge.fury.io/py/rope - :alt: Latest version - -.. |Download count badge| image:: https://img.shields.io/pypi/dm/rope.svg - :alt: Download count - -.. |ReadTheDocs status badge| image:: https://readthedocs.org/projects/rope/badge/?version=latest - :target: https://rope.readthedocs.io/en/latest/?badge=latest - :alt: Documentation Status - -Overview -======== - -`Rope`_ is the world's most advanced open source Python refactoring library -(yes, I totally stole that tagline from Postgres). - -.. _`rope`: https://github.com/python-rope/rope - - -Most Python syntax up to Python 3.10 is supported. Please file bugs and contribute -patches if you encounter gaps. - -Since version 1.0.0, rope no longer support running on Python 2. -If you need Python 2 support, then check out the `python2` branch or the 0.x.x -releases. - -Getting Started -=============== - -* `Documentation `_ -* `How to use Rope in my IDE or Text editor? `_ -* `Configuration `_ -* `List of features `_ -* `Overview of some of rope's features `_ -* `Using as a library `_ -* `Contributing `_ - -Why use Rope? -============= - -- Rope aims to provide powerful and safe refactoring -- Rope is light on dependency, Rope only depends on Python itself -- Unlike PyRight or PyLance, Rope does not depend on Node.js -- Unlike PyLance or PyCharm, Rope is open source. -- Unlike PyRight and PyLance, Rope is written in Python itself, so if you experience problems, you would be able to debug and hack it yourself in a language that you are already familiar with -- In comparison to Jedi, Rope is focused on refactoring. While Jedi provides some basic refactoring capabilities, Rope supports many more advanced refactoring operations and options that Jedi does not. - - -Bug Reports -=========== - -Send your bug reports and feature requests at `python-rope's issue tracker`_ in GitHub. - -.. _`python-rope's issue tracker`: https://github.com/python-rope/rope/issues - - -Maintainers -=========== - -Current active maintainer of Rope is Lie Ryan (`@lieryan`_). - -Special Thanks -============== - -Many thanks the following people: - -- Ali Gholami Rudi (`@aligrudi`_) for initially creating the initial Rope project and most of Rope's code -- Matej Cepl (`@mcepl`_) as former long-time Rope maintainer -- Nick Smith (`@soupytwist`_) as former Rope maintainer -- `all of our current and former contributors`_ -- `all authors of editor integrations`_ -- all maintainers of distro/package managers - -.. _`@aligrudi`: https://github.com/aligrudi -.. _`@soupytwist`: https://github.com/soupytwist -.. _`@lieryan`: https://github.com/lieryan -.. _`@mcepl`: https://github.com/mcepl -.. _`all of our current and former contributors`: https://github.com/python-rope/rope/blob/master/CONTRIBUTORS.md -.. _`all authors of editor integrations`: https://github.com/python-rope/rope/wiki/How-to-use-Rope-in-my-IDE-or-Text-editor%3F - -Packaging Status -================ - -.. image:: https://repology.org/badge/vertical-allrepos/python:rope.svg?exclude_unsupported=1 - :target: https://repology.org/project/python:rope/versions - :alt: Packaging status - -.. image:: https://repology.org/badge/vertical-allrepos/rope.svg?exclude_unsupported=1 - :target: https://repology.org/project/rope/versions - :alt: Packaging status - -License -======= - -This program is under the terms of LGPL v3+ (GNU Lesser General Public License). -Have a look at `COPYING`_ for more information. - -.. _`COPYING`: COPYING +See the `original readme file`_ for further details. From b93951f77f6e6ccd7444beb60d0c9bd41be5929a Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 19 Feb 2023 19:07:11 -0600 Subject: [PATCH 97/99] Add original readme --- README-Original.rst | 113 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 README-Original.rst diff --git a/README-Original.rst b/README-Original.rst new file mode 100644 index 000000000..52d229431 --- /dev/null +++ b/README-Original.rst @@ -0,0 +1,113 @@ + +.. _GitHub python-rope / rope: https://github.com/python-rope/rope + + +========================================================================= + rope -- the world's most advanced open source Python refactoring library +========================================================================= + +|Build status badge| |Latest version badge| |Download count badge| |ReadTheDocs status badge| + +.. |Build status badge| image:: https://github.com/python-rope/rope/actions/workflows/main.yml/badge.svg + :target: https://github.com/python-rope/rope/actions/workflows/main.yml + :alt: Build Status + +.. |Latest version badge| image:: https://badge.fury.io/py/rope.svg + :target: https://badge.fury.io/py/rope + :alt: Latest version + +.. |Download count badge| image:: https://img.shields.io/pypi/dm/rope.svg + :alt: Download count + +.. |ReadTheDocs status badge| image:: https://readthedocs.org/projects/rope/badge/?version=latest + :target: https://rope.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +Overview +======== + +`Rope`_ is the world's most advanced open source Python refactoring library +(yes, I totally stole that tagline from Postgres). + +.. _`rope`: https://github.com/python-rope/rope + + +Most Python syntax up to Python 3.10 is supported. Please file bugs and contribute +patches if you encounter gaps. + +Since version 1.0.0, rope no longer support running on Python 2. +If you need Python 2 support, then check out the `python2` branch or the 0.x.x +releases. + +Getting Started +=============== + +* `Documentation `_ +* `How to use Rope in my IDE or Text editor? `_ +* `Configuration `_ +* `List of features `_ +* `Overview of some of rope's features `_ +* `Using as a library `_ +* `Contributing `_ + +Why use Rope? +============= + +- Rope aims to provide powerful and safe refactoring +- Rope is light on dependency, Rope only depends on Python itself +- Unlike PyRight or PyLance, Rope does not depend on Node.js +- Unlike PyLance or PyCharm, Rope is open source. +- Unlike PyRight and PyLance, Rope is written in Python itself, so if you experience problems, you would be able to debug and hack it yourself in a language that you are already familiar with +- In comparison to Jedi, Rope is focused on refactoring. While Jedi provides some basic refactoring capabilities, Rope supports many more advanced refactoring operations and options that Jedi does not. + + +Bug Reports +=========== + +Send your bug reports and feature requests at `python-rope's issue tracker`_ in GitHub. + +.. _`python-rope's issue tracker`: https://github.com/python-rope/rope/issues + + +Maintainers +=========== + +Current active maintainer of Rope is Lie Ryan (`@lieryan`_). + +Special Thanks +============== + +Many thanks the following people: + +- Ali Gholami Rudi (`@aligrudi`_) for initially creating the initial Rope project and most of Rope's code +- Matej Cepl (`@mcepl`_) as former long-time Rope maintainer +- Nick Smith (`@soupytwist`_) as former Rope maintainer +- `all of our current and former contributors`_ +- `all authors of editor integrations`_ +- all maintainers of distro/package managers + +.. _`@aligrudi`: https://github.com/aligrudi +.. _`@soupytwist`: https://github.com/soupytwist +.. _`@lieryan`: https://github.com/lieryan +.. _`@mcepl`: https://github.com/mcepl +.. _`all of our current and former contributors`: https://github.com/python-rope/rope/blob/master/CONTRIBUTORS.md +.. _`all authors of editor integrations`: https://github.com/python-rope/rope/wiki/How-to-use-Rope-in-my-IDE-or-Text-editor%3F + +Packaging Status +================ + +.. image:: https://repology.org/badge/vertical-allrepos/python:rope.svg?exclude_unsupported=1 + :target: https://repology.org/project/python:rope/versions + :alt: Packaging status + +.. image:: https://repology.org/badge/vertical-allrepos/rope.svg?exclude_unsupported=1 + :target: https://repology.org/project/rope/versions + :alt: Packaging status + +License +======= + +This program is under the terms of LGPL v3+ (GNU Lesser General Public License). +Have a look at `COPYING`_ for more information. + +.. _`COPYING`: COPYING From c0eabc4d0e2241190c2da1675b5496a86d8709c8 Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 19 Feb 2023 19:09:01 -0600 Subject: [PATCH 98/99] Create short readme --- README.rst | 115 ++--------------------------------------------------- 1 file changed, 4 insertions(+), 111 deletions(-) diff --git a/README.rst b/README.rst index 52d229431..831356408 100644 --- a/README.rst +++ b/README.rst @@ -1,113 +1,6 @@ +.. _Rope: https://github.com/python-rope/rope +.. _`original readme file`: README.rst -.. _GitHub python-rope / rope: https://github.com/python-rope/rope +A fork of `Rope`_ to develop a Theory of Operation. - -========================================================================= - rope -- the world's most advanced open source Python refactoring library -========================================================================= - -|Build status badge| |Latest version badge| |Download count badge| |ReadTheDocs status badge| - -.. |Build status badge| image:: https://github.com/python-rope/rope/actions/workflows/main.yml/badge.svg - :target: https://github.com/python-rope/rope/actions/workflows/main.yml - :alt: Build Status - -.. |Latest version badge| image:: https://badge.fury.io/py/rope.svg - :target: https://badge.fury.io/py/rope - :alt: Latest version - -.. |Download count badge| image:: https://img.shields.io/pypi/dm/rope.svg - :alt: Download count - -.. |ReadTheDocs status badge| image:: https://readthedocs.org/projects/rope/badge/?version=latest - :target: https://rope.readthedocs.io/en/latest/?badge=latest - :alt: Documentation Status - -Overview -======== - -`Rope`_ is the world's most advanced open source Python refactoring library -(yes, I totally stole that tagline from Postgres). - -.. _`rope`: https://github.com/python-rope/rope - - -Most Python syntax up to Python 3.10 is supported. Please file bugs and contribute -patches if you encounter gaps. - -Since version 1.0.0, rope no longer support running on Python 2. -If you need Python 2 support, then check out the `python2` branch or the 0.x.x -releases. - -Getting Started -=============== - -* `Documentation `_ -* `How to use Rope in my IDE or Text editor? `_ -* `Configuration `_ -* `List of features `_ -* `Overview of some of rope's features `_ -* `Using as a library `_ -* `Contributing `_ - -Why use Rope? -============= - -- Rope aims to provide powerful and safe refactoring -- Rope is light on dependency, Rope only depends on Python itself -- Unlike PyRight or PyLance, Rope does not depend on Node.js -- Unlike PyLance or PyCharm, Rope is open source. -- Unlike PyRight and PyLance, Rope is written in Python itself, so if you experience problems, you would be able to debug and hack it yourself in a language that you are already familiar with -- In comparison to Jedi, Rope is focused on refactoring. While Jedi provides some basic refactoring capabilities, Rope supports many more advanced refactoring operations and options that Jedi does not. - - -Bug Reports -=========== - -Send your bug reports and feature requests at `python-rope's issue tracker`_ in GitHub. - -.. _`python-rope's issue tracker`: https://github.com/python-rope/rope/issues - - -Maintainers -=========== - -Current active maintainer of Rope is Lie Ryan (`@lieryan`_). - -Special Thanks -============== - -Many thanks the following people: - -- Ali Gholami Rudi (`@aligrudi`_) for initially creating the initial Rope project and most of Rope's code -- Matej Cepl (`@mcepl`_) as former long-time Rope maintainer -- Nick Smith (`@soupytwist`_) as former Rope maintainer -- `all of our current and former contributors`_ -- `all authors of editor integrations`_ -- all maintainers of distro/package managers - -.. _`@aligrudi`: https://github.com/aligrudi -.. _`@soupytwist`: https://github.com/soupytwist -.. _`@lieryan`: https://github.com/lieryan -.. _`@mcepl`: https://github.com/mcepl -.. _`all of our current and former contributors`: https://github.com/python-rope/rope/blob/master/CONTRIBUTORS.md -.. _`all authors of editor integrations`: https://github.com/python-rope/rope/wiki/How-to-use-Rope-in-my-IDE-or-Text-editor%3F - -Packaging Status -================ - -.. image:: https://repology.org/badge/vertical-allrepos/python:rope.svg?exclude_unsupported=1 - :target: https://repology.org/project/python:rope/versions - :alt: Packaging status - -.. image:: https://repology.org/badge/vertical-allrepos/rope.svg?exclude_unsupported=1 - :target: https://repology.org/project/rope/versions - :alt: Packaging status - -License -======= - -This program is under the terms of LGPL v3+ (GNU Lesser General Public License). -Have a look at `COPYING`_ for more information. - -.. _`COPYING`: COPYING +See the `original readme file`_ for further details. From 52c6a566e1984a599fbc5ac04d0b126fe929c99d Mon Sep 17 00:00:00 2001 From: "Edward K. Ream" Date: Sun, 19 Feb 2023 19:12:20 -0600 Subject: [PATCH 99/99] Correct link to readme --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 831356408..eee4c0485 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ .. _Rope: https://github.com/python-rope/rope -.. _`original readme file`: README.rst +.. _`original readme file`: README-Original.rst A fork of `Rope`_ to develop a Theory of Operation.