Skip to content

Commit 062108d

Browse files
author
atollk
committed
Fixes from code review.
1 parent 1e8da81 commit 062108d

File tree

4 files changed

+63
-9
lines changed

4 files changed

+63
-9
lines changed

fs/base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,10 @@ def match(self, patterns, name, accept_prefix=False):
16611661
True
16621662
>>> my_fs.match(['*.jpg', '*.png'], 'foo.gif')
16631663
False
1664+
>>> my_fs.match(['dir/file.txt'], 'dir/', accept_prefix=True)
1665+
True
1666+
>>> my_fs.match(['dir/file.txt'], 'dir/gile.txt', accept_prefix=True)
1667+
False
16641668
16651669
Note:
16661670
If ``patterns`` is `None` (or ``['*']``), then this

fs/errors.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"OperationFailed",
4343
"OperationTimeout",
4444
"PathError",
45+
"PatternError",
4546
"PermissionDenied",
4647
"RemoteConnectionError",
4748
"RemoveRootError",
@@ -51,6 +52,7 @@
5152
"ResourceNotFound",
5253
"ResourceReadOnly",
5354
"Unsupported",
55+
"UnsupportedHash",
5456
]
5557

5658

@@ -346,3 +348,19 @@ class UnsupportedHash(ValueError):
346348
not supported by hashlib.
347349
348350
"""
351+
352+
353+
class PatternError(ValueError):
354+
"""A string pattern with invalid syntax was given."""
355+
356+
default_message = "pattern '{pattern}' is invalid at position {position}"
357+
358+
def __init__(self, pattern, position, exc=None, msg=None): # noqa: D107
359+
# type: (Text, int, Optional[Exception], Optional[Text]) -> None
360+
self.pattern = pattern
361+
self.position = position
362+
self.exc = exc
363+
super(ValueError, self).__init__()
364+
365+
def __reduce__(self):
366+
return type(self), (self.path, self.position, self.exc, self._msg)

fs/wildcard.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
import typing
1515

16+
from ._repr import make_repr
17+
from .errors import PatternError
1618
from .lrucache import LRUCache
1719

1820
if typing.TYPE_CHECKING:
@@ -142,6 +144,7 @@ def get_matcher(patterns, case_sensitive, accept_prefix=False):
142144

143145
class _PatternMatcher:
144146
def __init__(self, pattern, case_sensitive, accept_prefixes):
147+
self.pattern = pattern
145148
self.case_sensitive = case_sensitive
146149
self.accept_prefixes = accept_prefixes
147150

@@ -151,11 +154,11 @@ def __init__(self, pattern, case_sensitive, accept_prefixes):
151154
if pattern[i] == "[":
152155
start = i
153156
i = pattern.find("]", i) + 1
157+
if i == 0:
158+
raise PatternError(pattern, len(pattern) - 1)
154159
self.tokens.append(_PatternMatcherToken(pattern[start:i]))
155160
elif pattern[i] == "]":
156-
raise ValueError(
157-
pattern + " is not a valid wildcard pattern. (unmatched ])"
158-
)
161+
raise PatternError(pattern, i)
159162
elif pattern[i] == "?":
160163
self.tokens.append(_PatternMatcherToken("?"))
161164
i += 1
@@ -166,11 +169,7 @@ def __init__(self, pattern, case_sensitive, accept_prefixes):
166169
] == "*":
167170
asterik_len += 1
168171
if asterik_len > 2:
169-
raise ValueError(
170-
pattern
171-
+ " is not a valid wildcard pattern. "
172-
+ "(sequence of three or more *)"
173-
)
172+
raise PatternError(pattern, i + 2)
174173
self.tokens.append(_PatternMatcherToken("*" * asterik_len))
175174
i += asterik_len
176175
else:
@@ -194,13 +193,21 @@ def _match(self, tokens, text):
194193
else:
195194
return self._match(tokens[1:], text[1:]) or self._match(tokens, text[1:])
196195

196+
def __repr__(self):
197+
return make_repr(
198+
"_PatternMatcher",
199+
self.pattern,
200+
case_sensitive=(self.case_sensitive, None),
201+
accept_prefixes=(self.accept_prefixes, None),
202+
)
203+
197204

198205
class _PatternMatcherToken:
199206
def __init__(self, token_str):
200207
self.token_str = token_str
201208

202209
def __repr__(self):
203-
return "_PatternMatcherToken (" + self.token_str + ")"
210+
return "_PatternMatcherToken({!r})".format(self.token_str)
204211

205212
def match(self, character, case_sensitive):
206213
if self.token_str[0] == "[":

tests/test_wildcard.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,31 @@ def test_wildcard(self):
3535
self.assertTrue(wildcard.match("**.jpg", "foo/a.jpg"))
3636
self.assertTrue(wildcard.match("**", "foo/a.jpg"))
3737

38+
def test_wildcard_accept_prefix(self):
39+
self.assertTrue(wildcard.match("*.py", "file", accept_prefix=True))
40+
self.assertTrue(wildcard.match("????.py", "????", accept_prefix=True))
41+
self.assertTrue(wildcard.match("file.py", "file.p", accept_prefix=True))
42+
self.assertTrue(wildcard.match("file.py[co]", "file.p", accept_prefix=True))
43+
self.assertTrue(wildcard.match("file.py[co]", "file.p", accept_prefix=True))
44+
self.assertTrue(wildcard.match("file.py[!c]", "file.py", accept_prefix=True))
45+
self.assertTrue(wildcard.match("file.py[^]", "file.py^", accept_prefix=True))
46+
47+
self.assertTrue(wildcard.match("*.jpg", "file.py", accept_prefix=True))
48+
self.assertFalse(wildcard.match("toolong.py", "????.py", accept_prefix=True))
49+
self.assertFalse(wildcard.match("file.pyc", "file.pyca", accept_prefix=True))
50+
self.assertFalse(wildcard.match("file.py[co]", "file.pyx", accept_prefix=True))
51+
self.assertFalse(wildcard.match("file.py[!o]", "file.pyo", accept_prefix=True))
52+
self.assertTrue(wildcard.match("file.py[]", "f", accept_prefix=True))
53+
54+
self.assertTrue(wildcard.imatch("*.py", "FILE.p", accept_prefix=True))
55+
self.assertTrue(wildcard.imatch("*.py", "file.", accept_prefix=True))
56+
57+
self.assertFalse(wildcard.match("foo*.jpg", "foo/", accept_prefix=True))
58+
self.assertTrue(wildcard.match("foo**.jpg", "foo", accept_prefix=True))
59+
self.assertTrue(wildcard.match("foo**", "foo/", accept_prefix=True))
60+
self.assertTrue(wildcard.match("**.jpg", "foo", accept_prefix=True))
61+
self.assertTrue(wildcard.match("**", "foo/a.j", accept_prefix=True))
62+
3863
def test_match_any(self):
3964
self.assertTrue(wildcard.match_any([], "foo.py"))
4065
self.assertTrue(wildcard.imatch_any([], "foo.py"))

0 commit comments

Comments
 (0)