From ed4481f2d2708d47a25e828fd5be8980fbcfe1f4 Mon Sep 17 00:00:00 2001 From: Sebastiaan Zeeff Date: Fri, 9 Jul 2021 16:34:12 +0200 Subject: [PATCH] Address #44: raise informative exception for invalid git patterns We've addressed the issue that GitWildMatchPattern would raise a cryptic IndexError for invalid git patterns. Instead, we raise an informative exception explaining that an invalid pattern was encountered. This exception is raised for at least the following patterns: - `!` - `\` --- pathspec/patterns/gitwildmatch.py | 15 +++++++++++++++ pathspec/tests/test_gitwildmatch.py | 20 +++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/pathspec/patterns/gitwildmatch.py b/pathspec/patterns/gitwildmatch.py index 4b4831b..afd8f6b 100644 --- a/pathspec/patterns/gitwildmatch.py +++ b/pathspec/patterns/gitwildmatch.py @@ -25,6 +25,14 @@ _BYTES_ENCODING = 'latin1' +class GitWildMatchPatternError(ValueError): + """ + The :class:`GitWildMatchPatternError` indicates an invalid git wild match + pattern. + """ + pass + + class GitWildMatchPattern(RegexPattern): """ The :class:`GitWildMatchPattern` class represents a compiled Git @@ -56,6 +64,7 @@ def pattern_to_regex(cls, pattern): else: raise TypeError("pattern:{!r} is not a unicode or byte string.".format(pattern)) + original_pattern = pattern pattern = pattern.strip() if pattern.startswith('#'): @@ -137,6 +146,12 @@ def pattern_to_regex(cls, pattern): # according to `git check-ignore` (v2.4.1). pass + if not pattern_segs: + # After resolving the edge cases, we end up with no + # pattern at all. This must be because the pattern is + # invalid. + raise GitWildMatchPatternError("Invalid git pattern: %r" % (original_pattern,)) + if not pattern_segs[-1] and len(pattern_segs) > 1: # A pattern ending with a slash ('/') will match all # descendant paths if it is a directory but not if it is a diff --git a/pathspec/tests/test_gitwildmatch.py b/pathspec/tests/test_gitwildmatch.py index 682ad02..9868381 100644 --- a/pathspec/tests/test_gitwildmatch.py +++ b/pathspec/tests/test_gitwildmatch.py @@ -10,7 +10,7 @@ import pathspec.patterns.gitwildmatch import pathspec.util -from pathspec.patterns.gitwildmatch import GitWildMatchPattern +from pathspec.patterns.gitwildmatch import GitWildMatchPattern, GitWildMatchPatternError if sys.version_info[0] >= 3: unichr = chr @@ -528,3 +528,21 @@ def test_08_escape(self): escaped = r"file\!with\*weird\#naming_\[1\].t\?t" result = GitWildMatchPattern.escape(fname) self.assertEqual(result, escaped) + + def test_09_single_escape_fail(self): + """ + Test an escape on a line by itself. + """ + self._check_invalid_pattern("\\") + + def test_09_single_exclamation_mark_fail(self): + """ + Test an escape on a line by itself. + """ + self._check_invalid_pattern("!") + + def _check_invalid_pattern(self, git_ignore_pattern): + expected_message_pattern = re.escape(repr(git_ignore_pattern)) + with self.assertRaisesRegexp(GitWildMatchPatternError, expected_message_pattern): + GitWildMatchPattern(git_ignore_pattern) +