Skip to content

Commit 95db1bc

Browse files
authored
Add a fast path for NameSets without wildcards (#241)
When the set of ignored names doesn't use shell-style wildcards, we can use the faster `frozenset.__contains__` base implementation rather than the more expensive iteration-based fnmatch'ing approach. This is true for the default ignore list, and I expect its the more common case by far even for those who add their own ignored names. In a simple local benchmark, this results in a 2x speed improvement for that common (default) path, which I think justifies the small additional complexity.
1 parent bc1a7e4 commit 95db1bc

File tree

1 file changed

+12
-4
lines changed

1 file changed

+12
-4
lines changed

src/pep8ext_naming.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,18 @@ def err(self, node, code: str, **kwargs):
5555

5656

5757
class NameSet(frozenset[str]):
58-
"""A set of names that are matched using fnmatchcase."""
59-
60-
def __contains__(self, item) -> bool:
61-
return any(fnmatchcase(item, name) for name in self)
58+
"""A set of names that can be matched as Unix shell-style wildcards."""
59+
_fnmatch: bool = False
60+
61+
def __new__(cls, iterable: Iterable[str]):
62+
obj = super().__new__(cls, iterable)
63+
obj._fnmatch = any("*" in s or "?" in s or "[" in s for s in iterable)
64+
return obj
65+
66+
def __contains__(self, item: object, /) -> bool:
67+
if self._fnmatch and isinstance(item, str):
68+
return any(fnmatchcase(item, name) for name in self)
69+
return super().__contains__(item)
6270

6371

6472
class _FunctionType:

0 commit comments

Comments
 (0)