From 5e63cbef433f4bcef8f9aa0e827c2188fd6b3676 Mon Sep 17 00:00:00 2001 From: Elifarley Date: Wed, 11 Dec 2024 16:13:49 -0300 Subject: [PATCH 1/4] test: double-decorated identifier --- .../corpus/move.double-decorated-method/1.py | 28 +++++++++++++++++++ .../move.double-decorated-method/chat.xml | 20 +++++++++++++ .../expected.1.py | 28 +++++++++++++++++++ tests/test_corpus.py | 10 +++---- 4 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 tests/corpus/move.double-decorated-method/1.py create mode 100644 tests/corpus/move.double-decorated-method/chat.xml create mode 100644 tests/corpus/move.double-decorated-method/expected.1.py diff --git a/tests/corpus/move.double-decorated-method/1.py b/tests/corpus/move.double-decorated-method/1.py new file mode 100644 index 0000000..090cc25 --- /dev/null +++ b/tests/corpus/move.double-decorated-method/1.py @@ -0,0 +1,28 @@ +import functools + + +class SpyderKernel(IPythonKernel): + """Spyder kernel for Jupyter.""" + + shell_class = SpyderShell + @comm_handler + def safe_exec(self, filename): + """Safely execute a file using IPKernelApp._exec_file.""" + self.parent._exec_file(filename) + + @comm_handler + @functools.lru_cache(32) + def get_fault_text(self, fault_filename, main_id, ignore_ids): + """Get fault text from old run.""" + # Read file + try: + with open(fault_filename, 'r') as f: + fault = f.read() + except FileNotFoundError: + return + return text + + def get_system_threads_id(self): + """Return the list of system threads id.""" + ignore_threads = [ + ] diff --git a/tests/corpus/move.double-decorated-method/chat.xml b/tests/corpus/move.double-decorated-method/chat.xml new file mode 100644 index 0000000..1ffa66e --- /dev/null +++ b/tests/corpus/move.double-decorated-method/chat.xml @@ -0,0 +1,20 @@ + +```CEDARScript +-- 1. Move the `get_fault_text` method from the `SpyderKernel` class to be a top-level function +UPDATE METHOD "SpyderKernel.get_fault_text" +FROM FILE "1.py" +MOVE WHOLE +INSERT BEFORE CLASS "SpyderKernel" +RELATIVE INDENTATION 0; + +-- 2. Update the copied function to remove references to `self` +UPDATE FUNCTION "get_fault_text" +FROM FILE r"1.py" +REPLACE WHOLE WITH CASE +WHEN REGEX r'''def get_fault_text\(''' THEN SUB +r'''def get_fault_text\(self, fault_filename, main_id, ignore_ids\):''' +r'''def get_fault_text(fault_filename, main_id, ignore_ids):''' +END; + +``` + diff --git a/tests/corpus/move.double-decorated-method/expected.1.py b/tests/corpus/move.double-decorated-method/expected.1.py new file mode 100644 index 0000000..6e01d81 --- /dev/null +++ b/tests/corpus/move.double-decorated-method/expected.1.py @@ -0,0 +1,28 @@ +import functools + + +@comm_handler +@functools.lru_cache(32) +def get_fault_text(fault_filename, main_id, ignore_ids): + """Get fault text from old run.""" + # Read file + try: + with open(fault_filename, 'r') as f: + fault = f.read() + except FileNotFoundError: + return + return text +class SpyderKernel(IPythonKernel): + """Spyder kernel for Jupyter.""" + + shell_class = SpyderShell + @comm_handler + def safe_exec(self, filename): + """Safely execute a file using IPKernelApp._exec_file.""" + self.parent._exec_file(filename) + + + def get_system_threads_id(self): + """Return the list of system threads id.""" + ignore_threads = [ + ] diff --git a/tests/test_corpus.py b/tests/test_corpus.py index c66d1ef..0408725 100644 --- a/tests/test_corpus.py +++ b/tests/test_corpus.py @@ -7,6 +7,7 @@ from cedarscript_editor import find_commands, CEDARScriptEditor +_no_windows = '!nowindows' def get_test_cases() -> list[str]: """Get all test cases from tests/corpus directory. @@ -41,9 +42,8 @@ def editor(tmp_path_factory): @pytest.mark.parametrize('test_case', get_test_cases()) def test_corpus(editor: CEDARScriptEditor, test_case: str): """Test CEDARScript commands from chat.xml files in corpus.""" - if test_case.casefold().endswith('!nowindows'): - if sys.platform == 'win32': - pytest.skip(f"Cannot run under Windows: {test_case.removesuffix('!nowindows')}") + if test_case.casefold().endswith(_no_windows) and sys.platform == 'win32': + pytest.skip(f"Cannot run under Windows: {test_case.removesuffix(_no_windows)}") try: corpus_dir = Path(__file__).parent / 'corpus' @@ -95,10 +95,10 @@ def check_expected_files(dir_path: Path): continue # Find corresponding expected file in test directory rel_path = path.relative_to(editor.root_path) - if str(rel_path).startswith("."): + if str(rel_path).startswith(".") or str(rel_path).endswith("~"): continue expected_file = test_dir / f"expected.{rel_path}" - assert expected_file.exists(), f"'expected.*' file not found: {expected_file}" + assert expected_file.exists(), f"'expected.*' file not found: '{expected_file}'" expected_content = file_to_lines(expected_file, rel_path) actual_content = file_to_lines(path, rel_path) From 3fce85a6739039c42e58cec915f4c399d7fa6436 Mon Sep 17 00:00:00 2001 From: Elifarley Date: Wed, 11 Dec 2024 16:15:29 -0300 Subject: [PATCH 2/4] fix: double-decorated identifier --- pyproject.toml | 1 + .../tree_sitter_identifier_finder.py | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 98eae24..f4a6a7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ classifiers = [ ] keywords = ["cedarscript", "code-editing", "refactoring", "code-analysis", "sql-like", "ai-assisted-development"] dependencies = [ + "orgecc-pylib>=0.1.3", "cedarscript-ast-parser>=0.6.1", "grep-ast==0.4.1", # https://github.com/tree-sitter/py-tree-sitter/issues/303 diff --git a/src/cedarscript_editor/tree_sitter_identifier_finder.py b/src/cedarscript_editor/tree_sitter_identifier_finder.py index c273a96..94deb48 100644 --- a/src/cedarscript_editor/tree_sitter_identifier_finder.py +++ b/src/cedarscript_editor/tree_sitter_identifier_finder.py @@ -9,7 +9,7 @@ from text_manipulation.range_spec import IdentifierBoundaries, RangeSpec, ParentInfo, ParentRestriction from text_manipulation import IdentifierFinder from tree_sitter_languages import get_language, get_parser - +from pylibtreesitter import nodes_by_type_suffix from .tree_sitter_identifier_queries import LANG_TO_TREE_SITTER_QUERY """ @@ -261,7 +261,11 @@ def find_parent_definition(node): node = node.parent if node.type.endswith('_definition'): if node.type == 'decorated_definition': - node = node.named_children[0].next_named_sibling + node = nodes_by_type_suffix(node.named_children, '_definition') + if node: + if len(node) > 1: + raise ValueError(f'{len(node)} parent definitions found: {node}') + return node[0] return node return None @@ -281,9 +285,11 @@ def capture2identifier_boundaries(captures, lines: Sequence[str]) -> list[Identi for capture in captures: unique_captures[f'{capture.range[0]}:{capture.capture_type}'] = capture # unique_captures={ - # '157:function.decorator': CaptureInfo(capture_type='function.decorator', node=), - # '158:function.definition': CaptureInfo(capture_type='function.definition', node=), - # '159:function.body': CaptureInfo(capture_type='function.body', node=) + # '14:function.definition': CaptureInfo(capture_type='function.definition', node=), + # '12:function.decorator': CaptureInfo(capture_type='function.decorator', node=), + # '13:function.decorator': CaptureInfo(capture_type='function.decorator', node=), + # '15:function.body': CaptureInfo(capture_type='function.body', node=), + # '15:function.docstring': CaptureInfo(capture_type='function.docstring', node=) # } return associate_identifier_parts(sort_captures(unique_captures), lines) From 81220ebdc945fd555fa0b6df8917461a162a35ac Mon Sep 17 00:00:00 2001 From: Elifarley Date: Wed, 11 Dec 2024 16:15:54 -0300 Subject: [PATCH 3/4] queries: simplification --- .../tree_sitter_identifier_queries.py | 26 +------------------ src/text_manipulation/range_spec.py | 2 +- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/cedarscript_editor/tree_sitter_identifier_queries.py b/src/cedarscript_editor/tree_sitter_identifier_queries.py index 0253d9b..ad9f2c5 100644 --- a/src/cedarscript_editor/tree_sitter_identifier_queries.py +++ b/src/cedarscript_editor/tree_sitter_identifier_queries.py @@ -36,8 +36,7 @@ . (expression_statement (string) @{type}.docstring)? - . - ) @{type}.body + ) @{type}.body """ _definition_base_template = """ @@ -63,29 +62,6 @@ {common_body} ) @function.definition ) - -; Methods in Classes -(class_definition - body: (block - (function_definition - {definition_base} - {common_body} - ) @function.definition - ) -) - -; Decorated Methods in Classes -(class_definition - body: (block - (decorated_definition - (decorator)+ @function.decorator - (function_definition - {definition_base} - {common_body} - ) @function.definition - ) - ) -) """.format( definition_base=_definition_base_template.format(type="function"), common_body=_common_template.format(type="function") diff --git a/src/text_manipulation/range_spec.py b/src/text_manipulation/range_spec.py index 605d5a8..1f9a6e8 100644 --- a/src/text_manipulation/range_spec.py +++ b/src/text_manipulation/range_spec.py @@ -366,7 +366,7 @@ def start_line(self) -> int: @property def body_start_line(self) -> int: """Return the 1-indexed start line of the identifier's body.""" - return self.body.start + 1 + return self.body.start + 1 if self.body else None @property def end_line(self) -> int: From 17a2e51661fe5fe0d7981da0254b295dbf2eb91f Mon Sep 17 00:00:00 2001 From: Elifarley Date: Wed, 11 Dec 2024 16:30:31 -0300 Subject: [PATCH 4/4] use src/version/_version.py; .gitignore config --- .gitignore | 8 ++++++++ .idea/.gitignore | 3 +++ pyproject.toml | 4 ++-- src/cedarscript_editor/__init__.py | 2 +- src/text_manipulation/__init__.py | 2 ++ src/version/__init__.py | 3 +++ 6 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 src/version/__init__.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3983192 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/src/version/_version.py +src/*.egg-info +dist +build +out +.coverage +.*.history* +*.tags.cache* diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/pyproject.toml b/pyproject.toml index f4a6a7e..d55214e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,13 +58,13 @@ package-dir = {"" = "src"} # >>> SETUPTOOLS_SCM_PRETEND_VERSION=0.0.2 python -m build # To dry-run and see version: # >>> python -m setuptools_scm -write_to = "src/cedarscript_editor/_version.py" +write_to = "src/version/_version.py" # Append .post{number of commits} to your version if there are commits after the last tag. version_scheme = "post-release" [tool.setuptools.packages.find] where = ["src"] -include = ["cedarscript_editor*", "text_manipulation*"] +include = ["version", "cedarscript_editor*", "text_manipulation*"] exclude = ["cedarscript_ast_parser.tests*"] namespaces = false diff --git a/src/cedarscript_editor/__init__.py b/src/cedarscript_editor/__init__.py index c7b6dcf..c7b0617 100644 --- a/src/cedarscript_editor/__init__.py +++ b/src/cedarscript_editor/__init__.py @@ -1,4 +1,4 @@ -from ._version import __version__ +from version import __version__ import re from .cedarscript_editor import CEDARScriptEditor from cedarscript_ast_parser import CEDARScriptASTParser diff --git a/src/text_manipulation/__init__.py b/src/text_manipulation/__init__.py index 1a8552b..96a6f58 100644 --- a/src/text_manipulation/__init__.py +++ b/src/text_manipulation/__init__.py @@ -1,3 +1,4 @@ +from version import __version__ from .line_kit import get_line_indent_count, extract_indentation from .range_spec import RangeSpec, IdentifierBoundaries from .text_editor_kit import read_file, write_file, bow_to_search_range @@ -5,6 +6,7 @@ from .indentation_kit import IndentationInfo __all__ = [ + "__version__", "IndentationInfo", "IdentifierBoundaries", "IdentifierFinder", diff --git a/src/version/__init__.py b/src/version/__init__.py new file mode 100644 index 0000000..32495d2 --- /dev/null +++ b/src/version/__init__.py @@ -0,0 +1,3 @@ +from ._version import version + +__version__ = version pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy