Skip to content

Commit 3d044f4

Browse files
committed
Specialize patterns
1 parent fad67b1 commit 3d044f4

File tree

4 files changed

+75
-7
lines changed

4 files changed

+75
-7
lines changed

pathspec/gitignore.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"""
4646

4747

48-
class GitIgnoreSpec(PathSpec):
48+
class GitIgnoreSpec(PathSpec[GitIgnoreSpecPattern]):
4949
"""
5050
The :class:`GitIgnoreSpec` class extends :class:`.PathSpec` to replicate
5151
*gitignore* behavior. This is uses :class:`.GitIgnoreSpecPattern` to fully

pathspec/pathspec.py

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@
1313
zip_longest)
1414
from typing import (
1515
Callable, # Replaced by `collections.abc.Callable` in 3.9.2.
16+
Generic,
17+
Literal,
1618
Optional, # Replaced by `X | None` in 3.10.
1719
TypeVar,
1820
Union, # Replaced by `X | Y` in 3.10.
19-
cast)
21+
cast,
22+
overload)
2023

2124
Self = TypeVar("Self", bound='PathSpec')
2225
"""
@@ -32,30 +35,33 @@
3235
make_pathspec_backend)
3336
from pathspec.pattern import (
3437
Pattern)
38+
from pathspec.patterns.gitignore.basic import (
39+
GitIgnoreBasicPattern)
3540
from pathspec._typing import (
3641
AnyStr, # Removed in 3.18.
3742
deprecated) # Added in 3.13.
3843
from pathspec.util import (
3944
CheckResult,
4045
StrPath,
46+
TPattern,
4147
TStrPath,
4248
TreeEntry,
4349
_is_iterable,
4450
normalize_file)
4551

4652

47-
class PathSpec(object):
53+
class PathSpec(Generic[TPattern]):
4854
"""
4955
The :class:`PathSpec` class is a wrapper around a list of compiled
5056
:class:`.Pattern` instances.
5157
"""
5258

5359
def __init__(
5460
self,
55-
patterns: Union[Sequence[Pattern], Iterable[Pattern]],
61+
patterns: Union[Sequence[TPattern], Iterable[TPattern]],
5662
*,
5763
backend: Union[BackendNamesHint, str, None] = None,
58-
_test_backend_factory: Optional[Callable[[Sequence[Pattern]], _Backend]] = None,
64+
_test_backend_factory: Optional[Callable[[Sequence[TPattern]], _Backend]] = None,
5965
) -> None:
6066
"""
6167
Initializes the :class:`.PathSpec` instance.
@@ -92,7 +98,7 @@ def __init__(
9298
*_backend_name* (:class:`str`) is the name of backend to use.
9399
"""
94100

95-
self.patterns: Sequence[Pattern] = patterns
101+
self.patterns: Sequence[TPattern] = patterns
96102
"""
97103
*patterns* (:class:`~collections.abc.Sequence` of :class:`.Pattern`)
98104
contains the compiled patterns.
@@ -225,6 +231,42 @@ def check_tree_files(
225231
files = util.iter_tree_files(root, on_error=on_error, follow_links=follow_links)
226232
yield from self.check_files(files)
227233

234+
@overload
235+
@classmethod
236+
def from_lines(
237+
cls: type[PathSpec],
238+
pattern_factory: Literal['gitignore'],
239+
lines: Iterable[AnyStr],
240+
*,
241+
backend: Union[BackendNamesHint, str, None] = None,
242+
_test_backend_factory: Optional[Callable[[Sequence[Pattern]], _Backend]] = None,
243+
) -> PathSpec[GitIgnoreBasicPattern]:
244+
...
245+
246+
@overload
247+
@classmethod
248+
def from_lines(
249+
cls: type[PathSpec],
250+
pattern_factory: Callable[[AnyStr], TPattern],
251+
lines: Iterable[AnyStr],
252+
*,
253+
backend: Union[BackendNamesHint, str, None] = None,
254+
_test_backend_factory: Optional[Callable[[Sequence[TPattern]], _Backend]] = None,
255+
) -> PathSpec[TPattern]:
256+
...
257+
258+
@overload
259+
@classmethod
260+
def from_lines(
261+
cls: type[PathSpec],
262+
pattern_factory: Union[str, Callable[[AnyStr], Pattern]],
263+
lines: Iterable[AnyStr],
264+
*,
265+
backend: Union[BackendNamesHint, str, None] = None,
266+
_test_backend_factory: Optional[Callable[[Sequence[Pattern]], _Backend]] = None,
267+
) -> PathSpec[Pattern]:
268+
...
269+
228270
@classmethod
229271
def from_lines(
230272
cls: type[Self],

pathspec/util.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030

3131
StrPath = Union[str, os.PathLike[str]]
3232

33+
TPattern = TypeVar('TPattern', bound=Pattern)
34+
"""
35+
Type variable for :class:`.Pattern`. This is used by :class:`pathspec.pathspec.PathSpec`
36+
to specialize the type of patterns.
37+
"""
38+
3339
TStrPath = TypeVar("TStrPath", bound=StrPath)
3440
"""
3541
Type variable for :class:`str` or :class:`os.PathLike`.

tests/test_04_pathspec.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
Path)
2020
from typing import (
2121
Callable, # Replaced by `collections.abc.Callable` in 3.9.2.
22-
Optional) # Replaced by `X | None` in 3.10.
22+
Literal,
23+
Optional, # Replaced by `X | None` in 3.10.
24+
overload)
2325
from unittest import (
2426
SkipTest)
2527

@@ -38,6 +40,8 @@
3840
Pattern)
3941
from pathspec.patterns.gitignore.base import (
4042
GitIgnorePatternError)
43+
from pathspec.patterns.gitignore.basic import (
44+
GitIgnoreBasicPattern)
4145
from pathspec._typing import (
4246
AnyStr) # Removed in 3.18.
4347
from pathspec.util import (
@@ -89,6 +93,22 @@ def make_files(self, files: Iterable[str]) -> None:
8993
"""
9094
return make_files(self.temp_dir, files)
9195

96+
@overload
97+
def parameterize_from_lines(
98+
self,
99+
pattern_factory: Literal['gitignore'],
100+
lines: Iterable[AnyStr],
101+
) -> Iterator[Callable[[], AbstractContextManager[PathSpec[GitIgnoreBasicPattern]]]]:
102+
...
103+
104+
@overload
105+
def parameterize_from_lines(
106+
self,
107+
pattern_factory: str,
108+
lines: Iterable[AnyStr],
109+
) -> Iterator[Callable[[], AbstractContextManager[PathSpec[Pattern]]]]:
110+
...
111+
92112
def parameterize_from_lines(
93113
self,
94114
pattern_factory: str,

0 commit comments

Comments
 (0)