mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-05 10:13:46 +00:00
fix: allow non-existent paths in ignore check
The _is_ignored_relative_path method used to raise FileNotFoundError when checking a path that does not exist on disk. This prevented editing tools (replace_content, insert_after_symbol, etc.) from operating on newly created files. Since a non-existent file cannot be matched by ignore patterns, returning False (not ignored) is semantically correct and safe. Changes: - _is_ignored_relative_path: return False instead of raising for non-existent paths, with a debug log message - validate_relative_path docstring: updated to reflect new behavior - Added 3 test cases covering non-existent path scenarios
This commit is contained in:
1 parent
981f560fa3
commit
9c19d5f7f8
3 files changed
+36
-6
No files matched your search
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
Status of the `main` branch. Changes prior to the next official version change will appear here.
|
Status of the `main` branch. Changes prior to the next official version change will appear here.
|
||||||
|
|
||||||
|
* General:
|
||||||
|
- Not existing paths return `False` on is ignored checks (instead of raising an error)
|
||||||
|
|
||||||
# v1.5.1 (2026-05-18)
|
# v1.5.1 (2026-05-18)
|
||||||
|
|
||||||
* General:
|
* General:
|
||||||
|
|||||||
@@ -191,8 +191,8 @@ class Project(ToStringMixin):
|
|||||||
|
|
||||||
def _is_ignored_relative_path(self, relative_path: str | Path, ignore_non_source_files: bool = True) -> bool:
|
def _is_ignored_relative_path(self, relative_path: str | Path, ignore_non_source_files: bool = True) -> bool:
|
||||||
"""
|
"""
|
||||||
Determine whether an existing path should be ignored based on file type and ignore patterns.
|
Determine whether a path should be ignored based on file type and ignore patterns.
|
||||||
Raises `FileNotFoundError` if the path does not exist.
|
Returns False for non-existent paths since they cannot be matched by ignore patterns.
|
||||||
|
|
||||||
:param relative_path: Relative path to check
|
:param relative_path: Relative path to check
|
||||||
:param ignore_non_source_files: whether files that are not source files (according to the file masks
|
:param ignore_non_source_files: whether files that are not source files (according to the file masks
|
||||||
@@ -208,7 +208,8 @@ class Project(ToStringMixin):
|
|||||||
|
|
||||||
abs_path = os.path.join(self.project_root, relative_path)
|
abs_path = os.path.join(self.project_root, relative_path)
|
||||||
if not os.path.exists(abs_path):
|
if not os.path.exists(abs_path):
|
||||||
raise FileNotFoundError(f"File {abs_path} not found, the ignore check cannot be performed")
|
log.debug(f"Path {abs_path} does not exist, skipping ignore check")
|
||||||
|
return False
|
||||||
|
|
||||||
# Check file extension if it's a file
|
# Check file extension if it's a file
|
||||||
is_file = os.path.isfile(abs_path)
|
is_file = os.path.isfile(abs_path)
|
||||||
@@ -284,10 +285,11 @@ class Project(ToStringMixin):
|
|||||||
|
|
||||||
def validate_relative_path(self, relative_path: str, require_not_ignored: bool = False) -> None:
|
def validate_relative_path(self, relative_path: str, require_not_ignored: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Validates that the given relative path to an existing file/dir is safe to read or edit,
|
Validates that the given relative path is safe to read or edit,
|
||||||
meaning it's inside the project directory.
|
meaning it's inside the project directory and not ignored.
|
||||||
|
|
||||||
Passing a path to a non-existing file will lead to a `FileNotFoundError`.
|
Non-existent paths are allowed (not considered ignored) to support
|
||||||
|
editing tools that create new files.
|
||||||
|
|
||||||
:param relative_path: the path to validate, relative to the project root
|
:param relative_path: the path to validate, relative to the project root
|
||||||
:param require_not_ignored: if True, the path must not be ignored according to the project's ignore settings
|
:param require_not_ignored: if True, the path must not be ignored according to the project's ignore settings
|
||||||
|
|||||||
@@ -102,6 +102,31 @@ class TestGlobalIgnoredPaths:
|
|||||||
assert project.is_ignored_path(str(self.project_path / "debug.log"))
|
assert project.is_ignored_path(str(self.project_path / "debug.log"))
|
||||||
assert not project.is_ignored_path(str(self.project_path / "main.py"))
|
assert not project.is_ignored_path(str(self.project_path / "main.py"))
|
||||||
|
|
||||||
|
def test_nonexistent_path_not_ignored(self) -> None:
|
||||||
|
"""Non-existent paths should return False (not ignored), not raise FileNotFoundError."""
|
||||||
|
project = _create_test_project(self.project_path)
|
||||||
|
nonexistent = str(self.project_path / "src" / "new_file.py")
|
||||||
|
assert not os.path.exists(nonexistent)
|
||||||
|
assert not project.is_ignored_path(nonexistent)
|
||||||
|
|
||||||
|
def test_nonexistent_path_with_ignore_patterns(self) -> None:
|
||||||
|
"""Non-existent paths matching ignore patterns still return False (cannot check)."""
|
||||||
|
project = _create_test_project(
|
||||||
|
self.project_path,
|
||||||
|
global_ignored_paths=["*.log"],
|
||||||
|
)
|
||||||
|
nonexistent = str(self.project_path / "nonexistent.log")
|
||||||
|
assert not os.path.exists(nonexistent)
|
||||||
|
# Should not raise, should not match the *.log pattern
|
||||||
|
assert not project.is_ignored_path(nonexistent)
|
||||||
|
|
||||||
|
def test_validate_relative_path_allows_nonexistent(self) -> None:
|
||||||
|
"""validate_relative_path with require_not_ignored should not raise for non-existent paths."""
|
||||||
|
project = _create_test_project(self.project_path)
|
||||||
|
nonexistent = "src/new_file.py"
|
||||||
|
# Should not raise
|
||||||
|
project.validate_relative_path(nonexistent, require_not_ignored=True)
|
||||||
|
|
||||||
|
|
||||||
class TestRegisteredProjectGlobalIgnoredPaths:
|
class TestRegisteredProjectGlobalIgnoredPaths:
|
||||||
"""RegisteredProject.get_project_instance() correctly passes global patterns to Project."""
|
"""RegisteredProject.get_project_instance() correctly passes global patterns to Project."""
|
||||||
|
|||||||
Reference in new issue
Block a user