From 33125287dc6f687c52aa99ad2406db78b902b3e4 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Thu, 23 Jul 2026 14:33:06 +0200 Subject: [PATCH] Remove obsolete glob pattern support in search_text, removing duplicate glob translation --- src/serena/util/text_utils.py | 28 ----------- test/serena/test_text_utils.py | 91 +--------------------------------- 2 files changed, 1 insertion(+), 118 deletions(-) diff --git a/src/serena/util/text_utils.py b/src/serena/util/text_utils.py index dad80252..670bae2e 100644 --- a/src/serena/util/text_utils.py +++ b/src/serena/util/text_utils.py @@ -117,34 +117,12 @@ class MatchedConsecutiveLines: return cls(lines=text_lines, source_file_path=source_file_path) -def glob_to_regex(glob_pat: str) -> str: - regex_parts: list[str] = [] - i = 0 - while i < len(glob_pat): - ch = glob_pat[i] - if ch == "*": - regex_parts.append(".*") - elif ch == "?": - regex_parts.append(".") - elif ch == "\\": - i += 1 - if i < len(glob_pat): - regex_parts.append(re.escape(glob_pat[i])) - else: - regex_parts.append("\\") - else: - regex_parts.append(re.escape(ch)) - i += 1 - return "".join(regex_parts) - - def search_text( pattern: str, content: str | None = None, source_file_path: str | None = None, context_lines_before: int = 0, context_lines_after: int = 0, - is_glob: bool = False, multiline: bool = True, ) -> list[MatchedConsecutiveLines]: """ @@ -156,8 +134,6 @@ def search_text( this has to be passed and the file will be read. :param context_lines_before: Number of context lines to include before matches :param context_lines_after: Number of context lines to include after matches - :param is_glob: If True, pattern is treated as a glob-like pattern (e.g., "*.py", "test_??.py") - and will be converted to regex internally :param multiline: whether to apply multi-line matching, enabling the flags re.DOTALL and re.MULTILINE :return: List of `TextSearchMatch` objects :raises: ValueError if the pattern is not valid @@ -173,10 +149,6 @@ def search_text( lines = TextUtils.split_lines(content) total_lines = len(lines) - # Convert pattern to a compiled regex if it's a string - if is_glob: - pattern = glob_to_regex(pattern) - # For multiline matches, optionally use DOTALL so '.' matches newlines flags = (re.MULTILINE | re.DOTALL) if multiline else 0 compiled_pattern = re.compile(pattern, flags) diff --git a/test/serena/test_text_utils.py b/test/serena/test_text_utils.py index 801a19d1..ce69ae55 100644 --- a/test/serena/test_text_utils.py +++ b/test/serena/test_text_utils.py @@ -1,10 +1,9 @@ -import re from collections.abc import Callable import pytest from serena.util.file_proxy import FileCollection, FileProxy -from serena.util.text_utils import LineType, MultiFileContentReplacer, glob_to_regex, search_files, search_text +from serena.util.text_utils import LineType, MultiFileContentReplacer, search_files, search_text class TestSearchText: @@ -177,94 +176,6 @@ class TestSearchText: match_lines = [line for line in multiline_match.lines if line.match_type == LineType.MATCH] assert len(match_lines) >= 3 - def test_search_text_with_glob_pattern(self): - """Test searching with glob-like patterns.""" - content = """ - class UserService: - def get_user(self, user_id): - return {"id": user_id, "name": "Test User"} - - def create_user(self, user_data): - print(f"Creating user: {user_data}") - return {"id": 123, **user_data} - - def update_user(self, user_id, user_data): - print(f"Updating user {user_id} with {user_data}") - return True - """ - - # Search with a glob pattern for all user methods - matches = search_text("*_user*", content=content, is_glob=True, multiline=False) - - assert len(matches) == 3 - assert "get_user" in matches[0].lines[0].line_content - assert "create_user" in matches[1].lines[0].line_content - assert "update_user" in matches[2].lines[0].line_content - - def test_search_text_with_complex_glob_pattern(self): - """Test searching with more complex glob patterns.""" - content = """ - def process_data(data): - return [transform(item) for item in data] - - def transform(item): - if isinstance(item, dict): - return {k: v.upper() if isinstance(v, str) else v for k, v in item.items()} - elif isinstance(item, list): - return [x * 2 for x in item if isinstance(x, (int, float))] - elif isinstance(item, str): - return item.upper() - else: - return item - """ - - # Search with a simplified glob pattern to find all isinstance occurrences - matches = search_text("*isinstance*", content=content, is_glob=True, multiline=False) - - # Should match lines with isinstance(item, dict) and isinstance(item, list) - assert len(matches) >= 2 - instance_matches = [ - line.line_content - for match in matches - for line in match.lines - if line.match_type == LineType.MATCH and "isinstance(item," in line.line_content - ] - assert len(instance_matches) >= 2 - assert any("isinstance(item, dict)" in line for line in instance_matches) - assert any("isinstance(item, list)" in line for line in instance_matches) - - def test_search_text_glob_with_special_chars(self): - """Glob patterns containing regex special characters should match literally.""" - content = """ - def func_square(): - print("value[42]") - - def func_curly(): - print("value{bar}") - """ - - matches_square = search_text(r"*\[42\]*", content=content, is_glob=True, multiline=False) - assert len(matches_square) == 1 - assert "[42]" in matches_square[0].lines[0].line_content - - matches_curly = search_text("*{bar}*", content=content, is_glob=True, multiline=False) - assert len(matches_curly) == 1 - assert "{bar}" in matches_curly[0].lines[0].line_content - - def test_glob_to_regex_question_matches_single_char(self): - """A glob '?' matches exactly one character, matching glob_match's documented semantics.""" - rx = glob_to_regex("a?c") - assert re.fullmatch(rx, "abc") is not None - assert re.fullmatch(rx, "ac") is None - assert re.fullmatch(rx, "abbc") is None - - def test_search_text_glob_question_single_char(self): - """search_text('c?t', is_glob=True) must match 'cat' (one char), not 'coat' (two chars).""" - content = "value_cat_end\nvalue_coat_end" - matches = search_text("c?t", content=content, is_glob=True, multiline=False) - assert len(matches) == 1 - assert "value_cat_end" in matches[0].lines[0].line_content - def test_search_text_no_matches(self): """Test searching with a pattern that doesn't match anything.""" content = """