Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-pathspec for openSUSE:Factory
checked in at 2022-01-07 12:44:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pathspec (Old)
and /work/SRC/openSUSE:Factory/.python-pathspec.new.1896 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pathspec"
Fri Jan 7 12:44:54 2022 rev:9 rq:943953 version:0.9.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pathspec/python-pathspec.changes
2021-06-11 22:29:53.322048556 +0200
+++
/work/SRC/openSUSE:Factory/.python-pathspec.new.1896/python-pathspec.changes
2022-01-07 12:45:28.031807374 +0100
@@ -1,0 +2,11 @@
+Wed Jan 5 10:29:55 UTC 2022 - Dirk M??ller <[email protected]>
+
+- update to 0.9.0:
+ * Raise `GitWildMatchPatternError` for invalid git patterns.
+ * Fix for duplicate leading double-asterisk, and edge cases.
+ * Fix matching absolute paths.
+ * API change: `util.normalize_files()` now returns a
+ `Dict[str, List[pathlike]]` instead of a `Dict[str, pathlike]`.
+ * Added type hinting.
+
+-------------------------------------------------------------------
Old:
----
pathspec-0.8.1.tar.gz
New:
----
pathspec-0.9.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pathspec.spec ++++++
--- /var/tmp/diff_new_pack.8XLIJT/_old 2022-01-07 12:45:28.739807866 +0100
+++ /var/tmp/diff_new_pack.8XLIJT/_new 2022-01-07 12:45:28.743807869 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-pathspec
#
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-pathspec
-Version: 0.8.1
+Version: 0.9.0
Release: 0
Summary: Utility library for gitignore style pattern matching of file
paths
License: MPL-2.0
++++++ pathspec-0.8.1.tar.gz -> pathspec-0.9.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/CHANGES.rst
new/pathspec-0.9.0/CHANGES.rst
--- old/pathspec-0.8.1/CHANGES.rst 2020-11-07 20:31:55.000000000 +0100
+++ new/pathspec-0.9.0/CHANGES.rst 2021-07-18 02:13:17.000000000 +0200
@@ -2,6 +2,21 @@
Change History
==============
+0.9.0 (2021-07-17)
+------------------
+
+- `Issue #44`_/`Issue #50`_: Raise `GitWildMatchPatternError` for invalid git
patterns.
+- `Issue #45`_: Fix for duplicate leading double-asterisk, and edge cases.
+- `Issue #46`_: Fix matching absolute paths.
+- API change: `util.normalize_files()` now returns a `Dict[str,
List[pathlike]]` instead of a `Dict[str, pathlike]`.
+- Added type hinting.
+
+.. _`Issue #44`: https://github.com/cpburnz/python-path-specification/issues/44
+.. _`Issue #45`: https://github.com/cpburnz/python-path-specification/pull/45
+.. _`Issue #46`: https://github.com/cpburnz/python-path-specification/issues/46
+.. _`Issue #50`: https://github.com/cpburnz/python-path-specification/pull/50
+
+
0.8.1 (2020-11-07)
------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/MANIFEST.in
new/pathspec-0.9.0/MANIFEST.in
--- old/pathspec-0.8.1/MANIFEST.in 2020-01-29 03:45:39.000000000 +0100
+++ new/pathspec-0.9.0/MANIFEST.in 2021-06-03 05:48:54.000000000 +0200
@@ -1,2 +1,3 @@
+include *.py
include *.rst
include LICENSE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/PKG-INFO new/pathspec-0.9.0/PKG-INFO
--- old/pathspec-0.8.1/PKG-INFO 2020-11-07 20:37:55.000000000 +0100
+++ new/pathspec-0.9.0/PKG-INFO 2021-07-18 02:27:56.000000000 +0200
@@ -1,12 +1,13 @@
-Metadata-Version: 1.2
+Metadata-Version: 2.1
Name: pathspec
-Version: 0.8.1
+Version: 0.9.0
Summary: Utility library for gitignore style pattern matching of file paths.
Home-page: https://github.com/cpburnz/python-path-specification
Author: Caleb P. Burns
Author-email: [email protected]
License: MPL 2.0
-Description: *pathspec*: Path Specification
+Description:
+ *pathspec*: Path Specification
==============================
*pathspec* is a utility library for pattern matching of file paths. So
@@ -159,9 +160,25 @@
.. _`Ruby gem`: https://github.com/highb/pathspec-ruby
+
Change History
==============
+ 0.9.0 (2021-07-17)
+ ------------------
+
+ - `Issue #44`_/`Issue #50`_: Raise `GitWildMatchPatternError` for
invalid git patterns.
+ - `Issue #45`_: Fix for duplicate leading double-asterisk, and edge
cases.
+ - `Issue #46`_: Fix matching absolute paths.
+ - API change: `util.normalize_files()` now returns a `Dict[str,
List[pathlike]]` instead of a `Dict[str, pathlike]`.
+ - Added type hinting.
+
+ .. _`Issue #44`:
https://github.com/cpburnz/python-path-specification/issues/44
+ .. _`Issue #45`:
https://github.com/cpburnz/python-path-specification/pull/45
+ .. _`Issue #46`:
https://github.com/cpburnz/python-path-specification/issues/46
+ .. _`Issue #50`:
https://github.com/cpburnz/python-path-specification/pull/50
+
+
0.8.1 (2020-11-07)
------------------
@@ -369,6 +386,7 @@
------------------
- Initial release.
+
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
@@ -382,8 +400,10 @@
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
-Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
+Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
+Description-Content-Type: text/x-rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec/__init__.py
new/pathspec-0.9.0/pathspec/__init__.py
--- old/pathspec-0.8.1/pathspec/__init__.py 2020-11-07 20:35:24.000000000
+0100
+++ new/pathspec-0.9.0/pathspec/__init__.py 2021-06-03 05:48:54.000000000
+0200
@@ -23,44 +23,18 @@
"""
from __future__ import unicode_literals
-__author__ = "Caleb P. Burns"
-__copyright__ = "Copyright ?? 2013-2020 Caleb P. Burns"
-__created__ = "2013-10-12"
-__credits__ = [
- "dahlia <https://github.com/dahlia>",
- "highb <https://github.com/highb>",
- "029xue <https://github.com/029xue>",
- "mikexstudios <https://github.com/mikexstudios>",
- "nhumrich <https://github.com/nhumrich>",
- "davidfraser <https://github.com/davidfraser>",
- "demurgos <https://github.com/demurgos>",
- "ghickman <https://github.com/ghickman>",
- "nvie <https://github.com/nvie>",
- "adrienverge <https://github.com/adrienverge>",
- "AndersBlomdell <https://github.com/AndersBlomdell>",
- "highb <https://github.com/highb>",
- "thmxv <https://github.com/thmxv>",
- "wimglenn <https://github.com/wimglenn>",
- "hugovk <https://github.com/hugovk>",
- "dcecile <https://github.com/dcecile>",
- "mroutis <https://github.com/mroutis>",
- "jdufresne <https://github.com/jdufresne>",
- "groodt <https://github.com/groodt>",
- "ftrofin <https://github.com/ftrofin>",
- "pykong <https://github.com/pykong>",
- "nhhollander <https://github.com/nhhollander>",
-]
-__email__ = "[email protected]"
-__license__ = "MPL 2.0"
-__project__ = "pathspec"
-__status__ = "Development"
-__updated__ = "2020-11-07"
-__version__ = "0.8.1"
-
from .pathspec import PathSpec
from .pattern import Pattern, RegexPattern
from .util import iter_tree, lookup_pattern, match_files, RecursionError
+from ._meta import (
+ __author__,
+ __copyright__,
+ __credits__,
+ __license__,
+ __version__,
+)
+
# Load pattern implementations.
from . import patterns
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec/_meta.py
new/pathspec-0.9.0/pathspec/_meta.py
--- old/pathspec-0.8.1/pathspec/_meta.py 1970-01-01 01:00:00.000000000
+0100
+++ new/pathspec-0.9.0/pathspec/_meta.py 2021-07-18 02:13:02.000000000
+0200
@@ -0,0 +1,43 @@
+# encoding: utf-8
+"""
+This module contains the project meta-data.
+"""
+
+__author__ = "Caleb P. Burns"
+__copyright__ = "Copyright ?? 2013-2021 Caleb P. Burns"
+__credits__ = [
+ "dahlia <https://github.com/dahlia>",
+ "highb <https://github.com/highb>",
+ "029xue <https://github.com/029xue>",
+ "mikexstudios <https://github.com/mikexstudios>",
+ "nhumrich <https://github.com/nhumrich>",
+ "davidfraser <https://github.com/davidfraser>",
+ "demurgos <https://github.com/demurgos>",
+ "ghickman <https://github.com/ghickman>",
+ "nvie <https://github.com/nvie>",
+ "adrienverge <https://github.com/adrienverge>",
+ "AndersBlomdell <https://github.com/AndersBlomdell>",
+ "highb <https://github.com/highb>",
+ "thmxv <https://github.com/thmxv>",
+ "wimglenn <https://github.com/wimglenn>",
+ "hugovk <https://github.com/hugovk>",
+ "dcecile <https://github.com/dcecile>",
+ "mroutis <https://github.com/mroutis>",
+ "jdufresne <https://github.com/jdufresne>",
+ "groodt <https://github.com/groodt>",
+ "ftrofin <https://github.com/ftrofin>",
+ "pykong <https://github.com/pykong>",
+ "nhhollander <https://github.com/nhhollander>",
+ "KOLANICH <https://github.com/KOLANICH>",
+ "JonjonHays <https://github.com/JonjonHays>",
+ "Isaac0616 <https://github.com/Isaac0616>",
+ "SebastiaanZ <https://github.com/SebastiaanZ>",
+ "RoelAdriaans <https://github.com/RoelAdriaans>",
+ "raviselker <https://github.com/raviselker>",
+ "johanvergeer <https://github.com/johanvergeer>",
+ "danjer <https://github.com/danjer>",
+ "jhbuhrman <https://github.com/jhbuhrman>",
+ "WPDOrdina <https://github.com/WPDOrdina>",
+]
+__license__ = "MPL 2.0"
+__version__ = "0.9.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec/compat.py
new/pathspec-0.9.0/pathspec/compat.py
--- old/pathspec-0.8.1/pathspec/compat.py 2020-04-07 05:10:57.000000000
+0200
+++ new/pathspec-0.9.0/pathspec/compat.py 2021-06-12 18:47:43.000000000
+0200
@@ -36,3 +36,6 @@
except ImportError:
# Python 2.7 - 3.5.
from collections import Container as Collection
+
+CollectionType = Collection
+IterableType = Iterable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec/pathspec.py
new/pathspec-0.9.0/pathspec/pathspec.py
--- old/pathspec-0.8.1/pathspec/pathspec.py 2020-11-07 20:27:35.000000000
+0100
+++ new/pathspec-0.9.0/pathspec/pathspec.py 2021-06-12 20:06:53.000000000
+0200
@@ -4,8 +4,34 @@
of files.
"""
+try:
+ from typing import (
+ Any,
+ AnyStr,
+ Callable,
+ Iterable,
+ Iterator,
+ Optional,
+ Text,
+ Union)
+except ImportError:
+ pass
+
+try:
+ # Python 3.6+ type hints.
+ from os import PathLike
+ from typing import Collection
+except ImportError:
+ pass
+
from . import util
-from .compat import Collection, iterkeys, izip_longest, string_types, unicode
+from .compat import (
+ CollectionType,
+ iterkeys,
+ izip_longest,
+ string_types)
+from .pattern import Pattern
+from .util import TreeEntry
class PathSpec(object):
@@ -15,6 +41,7 @@
"""
def __init__(self, patterns):
+ # type: (Iterable[Pattern]) -> None
"""
Initializes the :class:`PathSpec` instance.
@@ -22,13 +49,14 @@
yields each compiled pattern (:class:`.Pattern`).
"""
- self.patterns = patterns if isinstance(patterns, Collection)
else list(patterns)
+ self.patterns = patterns if isinstance(patterns,
CollectionType) else list(patterns)
"""
*patterns* (:class:`~collections.abc.Collection` of
:class:`.Pattern`)
contains the compiled patterns.
"""
def __eq__(self, other):
+ # type: (PathSpec) -> bool
"""
Tests the equality of this path-spec with *other*
(:class:`PathSpec`)
by comparing their :attr:`~PathSpec.patterns` attributes.
@@ -47,6 +75,7 @@
return len(self.patterns)
def __add__(self, other):
+ # type: (PathSpec) -> PathSpec
"""
Combines the :attr:`Pathspec.patterns` patterns from two
:class:`PathSpec` instances.
@@ -57,6 +86,7 @@
return NotImplemented
def __iadd__(self, other):
+ # type: (PathSpec) -> PathSpec
"""
Adds the :attr:`Pathspec.patterns` patterns from one
:class:`PathSpec`
instance to this instance.
@@ -69,6 +99,7 @@
@classmethod
def from_lines(cls, pattern_factory, lines):
+ # type: (Union[Text, Callable[[AnyStr], Pattern]],
Iterable[AnyStr]) -> PathSpec
"""
Compiles the pattern lines.
@@ -92,10 +123,11 @@
if not util._is_iterable(lines):
raise TypeError("lines:{!r} is not an
iterable.".format(lines))
- lines = [pattern_factory(line) for line in lines if line]
- return cls(lines)
+ patterns = [pattern_factory(line) for line in lines if line]
+ return cls(patterns)
def match_file(self, file, separators=None):
+ # type: (Union[Text, PathLike], Optional[Collection[Text]]) ->
bool
"""
Matches the file to this path-spec.
@@ -112,6 +144,7 @@
return util.match_file(self.patterns, norm_file)
def match_entries(self, entries, separators=None):
+ # type: (Iterable[TreeEntry], Optional[Collection[Text]]) ->
Iterator[TreeEntry]
"""
Matches the entries to this path-spec.
@@ -123,7 +156,7 @@
normalize. See :func:`~pathspec.util.normalize_file` for more
information.
- Returns the matched entries (:class:`~collections.abc.Iterable`
of
+ Returns the matched entries (:class:`~collections.abc.Iterator`
of
:class:`~util.TreeEntry`).
"""
if not util._is_iterable(entries):
@@ -135,6 +168,7 @@
yield entry_map[path]
def match_files(self, files, separators=None):
+ # type: (Iterable[Union[Text, PathLike]],
Optional[Collection[Text]]) -> Iterator[Union[Text, PathLike]]
"""
Matches the files to this path-spec.
@@ -147,18 +181,20 @@
normalize. See :func:`~pathspec.util.normalize_file` for more
information.
- Returns the matched files (:class:`~collections.abc.Iterable` of
- :class:`str`).
+ Returns the matched files (:class:`~collections.abc.Iterator` of
+ :class:`str` or :class:`pathlib.PurePath`).
"""
if not util._is_iterable(files):
raise TypeError("files:{!r} is not an
iterable.".format(files))
file_map = util.normalize_files(files, separators=separators)
matched_files = util.match_files(self.patterns,
iterkeys(file_map))
- for path in matched_files:
- yield file_map[path]
+ for norm_file in matched_files:
+ for orig_file in file_map[norm_file]:
+ yield orig_file
def match_tree_entries(self, root, on_error=None, follow_links=None):
+ # type: (Text, Optional[Callable], Optional[bool]) ->
Iterator[TreeEntry]
"""
Walks the specified root path for all files and matches them to
this
path-spec.
@@ -174,13 +210,14 @@
to walk symbolic links that resolve to directories. See
:func:`~pathspec.util.iter_tree_files` for more information.
- Returns the matched files (:class:`~collections.abc.Iterable` of
- :class:`str`).
+ Returns the matched files (:class:`~collections.abc.Iterator` of
+ :class:`.TreeEntry`).
"""
entries = util.iter_tree_entries(root, on_error=on_error,
follow_links=follow_links)
return self.match_entries(entries)
def match_tree_files(self, root, on_error=None, follow_links=None):
+ # type: (Text, Optional[Callable], Optional[bool]) ->
Iterator[Text]
"""
Walks the specified root path for all files and matches them to
this
path-spec.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec/pattern.py
new/pathspec-0.9.0/pathspec/pattern.py
--- old/pathspec-0.8.1/pathspec/pattern.py 2020-02-03 04:22:42.000000000
+0100
+++ new/pathspec-0.9.0/pathspec/pattern.py 2021-06-12 19:34:35.000000000
+0200
@@ -4,6 +4,18 @@
"""
import re
+try:
+ from typing import (
+ AnyStr,
+ Iterable,
+ Iterator,
+ Optional,
+ Pattern as RegexHint,
+ Text,
+ Tuple,
+ Union)
+except ImportError:
+ pass
from .compat import unicode
@@ -17,6 +29,7 @@
__slots__ = ('include',)
def __init__(self, include):
+ # type: (Optional[bool]) -> None
"""
Initializes the :class:`Pattern` instance.
@@ -33,6 +46,7 @@
"""
def match(self, files):
+ # type: (Iterable[Text]) -> Iterator[Text]
"""
Matches this pattern against the specified files.
@@ -55,6 +69,7 @@
__slots__ = ('regex',)
def __init__(self, pattern, include=None):
+ # type: (Union[AnyStr, RegexHint], Optional[bool]) -> None
"""
Initializes the :class:`RegexPattern` instance.
@@ -103,6 +118,7 @@
self.regex = regex
def __eq__(self, other):
+ # type: (RegexPattern) -> bool
"""
Tests the equality of this regex pattern with *other*
(:class:`RegexPattern`)
by comparing their :attr:`~Pattern.include` and
:attr:`~RegexPattern.regex`
@@ -114,6 +130,7 @@
return NotImplemented
def match(self, files):
+ # type: (Iterable[Text]) -> Iterable[Text]
"""
Matches this pattern against the specified files.
@@ -130,6 +147,7 @@
@classmethod
def pattern_to_regex(cls, pattern):
+ # type: (Text) -> Tuple[Text, bool]
"""
Convert the pattern into an uncompiled regular expression.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec/patterns/gitwildmatch.py
new/pathspec-0.9.0/pathspec/patterns/gitwildmatch.py
--- old/pathspec-0.8.1/pathspec/patterns/gitwildmatch.py 2020-02-03
04:22:42.000000000 +0100
+++ new/pathspec-0.9.0/pathspec/patterns/gitwildmatch.py 2021-07-18
02:05:09.000000000 +0200
@@ -8,6 +8,14 @@
import re
import warnings
+try:
+ from typing import (
+ AnyStr,
+ Optional,
+ Text,
+ Tuple)
+except ImportError:
+ pass
from .. import util
from ..compat import unicode
@@ -17,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
@@ -28,6 +44,7 @@
@classmethod
def pattern_to_regex(cls, pattern):
+ # type: (AnyStr) -> Tuple[Optional[AnyStr], Optional[bool]]
"""
Convert the pattern into a regular expression.
@@ -47,6 +64,7 @@
else:
raise TypeError("pattern:{!r} is not a unicode or byte
string.".format(pattern))
+ original_pattern = pattern
pattern = pattern.strip()
if pattern.startswith('#'):
@@ -63,7 +81,6 @@
include = None
elif pattern:
-
if pattern.startswith('!'):
# A pattern starting with an exclamation mark
('!') negates the
# pattern (exclude instead of include). Escape
the exclamation
@@ -80,11 +97,31 @@
# exclamation mark ('!').
pattern = pattern[1:]
+ # Allow a regex override for edge cases that cannot be
handled
+ # through normalization.
+ override_regex = None
+
# Split pattern into segments.
pattern_segs = pattern.split('/')
# Normalize pattern to make processing easier.
+ # EDGE CASE: Deal with duplicate double-asterisk
sequences.
+ # Collapse each sequence down to one double-asterisk.
Iterate over
+ # the segments in reverse and remove the duplicate
double
+ # asterisks as we go.
+ for i in range(len(pattern_segs) - 1, 0, -1):
+ prev = pattern_segs[i-1]
+ seg = pattern_segs[i]
+ if prev == '**' and seg == '**':
+ del pattern_segs[i]
+
+ if len(pattern_segs) == 2 and pattern_segs[0] == '**'
and not pattern_segs[1]:
+ # EDGE CASE: The '**/' pattern should match
everything except
+ # individual files in the root directory. This
case cannot be
+ # adequately handled through normalization. Use
the override.
+ override_regex = '^.+/.*$'
+
if not pattern_segs[0]:
# A pattern beginning with a slash ('/') will
only match paths
# directly on the root directory instead of any
descendant
@@ -109,58 +146,75 @@
# 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
regular file.
- # This is equivilent to "{pattern}/**". So, set
last segment to
- # double asterisks to include all descendants.
+ # A pattern ending with a slash ('/') will
match all
+ # descendant paths if it is a directory but not
if it is a
+ # regular file. This is equivalent to
"{pattern}/**". So, set
+ # last segment to a double-asterisk to include
all
+ # descendants.
pattern_segs[-1] = '**'
- # Build regular expression from pattern.
- output = ['^']
- need_slash = False
- end = len(pattern_segs) - 1
- for i, seg in enumerate(pattern_segs):
- if seg == '**':
- if i == 0 and i == end:
- # A pattern consisting solely
of double-asterisks ('**')
- # will match every path.
- output.append('.+')
- elif i == 0:
- # A normalized pattern
beginning with double-asterisks
- # ('**') will match any leading
path segments.
- output.append('(?:.+/)?')
- need_slash = False
- elif i == end:
- # A normalized pattern ending
with double-asterisks ('**')
- # will match any trailing path
segments.
- output.append('/.*')
+ if override_regex is None:
+ # Build regular expression from pattern.
+ output = ['^']
+ need_slash = False
+ end = len(pattern_segs) - 1
+ for i, seg in enumerate(pattern_segs):
+ if seg == '**':
+ if i == 0 and i == end:
+ # A pattern consisting
solely of double-asterisks ('**')
+ # will match every path.
+ output.append('.+')
+ elif i == 0:
+ # A normalized pattern
beginning with double-asterisks
+ # ('**') will match any
leading path segments.
+
output.append('(?:.+/)?')
+ need_slash = False
+ elif i == end:
+ # A normalized pattern
ending with double-asterisks ('**')
+ # will match any
trailing path segments.
+ output.append('/.*')
+ else:
+ # A pattern with inner
double-asterisks ('**') will match
+ # multiple (or zero)
inner path segments.
+
output.append('(?:/.+)?')
+ need_slash = True
+
+ elif seg == '*':
+ # Match single path segment.
+ if need_slash:
+ output.append('/')
+ output.append('[^/]+')
+ need_slash = True
+
else:
- # A pattern with inner
double-asterisks ('**') will match
- # multiple (or zero) inner path
segments.
- output.append('(?:/.+)?')
+ # Match segment glob pattern.
+ if need_slash:
+ output.append('/')
+
+
output.append(cls._translate_segment_glob(seg))
+ if i == end and include is True:
+ # A pattern ending
without a slash ('/') will match a file
+ # or a directory (with
paths underneath it). E.g., "foo"
+ # matches "foo",
"foo/bar", "foo/bar/baz", etc.
+ # EDGE CASE: However,
this does not hold for exclusion cases
+ # according to `git
check-ignore` (v2.4.1).
+
output.append('(?:/.*)?')
+
need_slash = True
- elif seg == '*':
- # Match single path segment.
- if need_slash:
- output.append('/')
- output.append('[^/]+')
- need_slash = True
- else:
- # Match segment glob pattern.
- if need_slash:
- output.append('/')
-
output.append(cls._translate_segment_glob(seg))
- if i == end and include is True:
- # A pattern ending without a
slash ('/') will match a file
- # or a directory (with paths
underneath it). E.g., "foo"
- # matches "foo", "foo/bar",
"foo/bar/baz", etc.
- # EDGE CASE: However, this does
not hold for exclusion cases
- # according to `git
check-ignore` (v2.4.1).
- output.append('(?:/.*)?')
- need_slash = True
- output.append('$')
- regex = ''.join(output)
+
+ output.append('$')
+ regex = ''.join(output)
+
+ else:
+ # Use regex override.
+ regex = override_regex
else:
# A blank pattern is a null-operation (neither includes
nor
@@ -175,6 +229,7 @@
@staticmethod
def _translate_segment_glob(pattern):
+ # type: (Text) -> Text
"""
Translates the glob pattern to a regular expression. This is
used in
the constructor to translate a path segment glob pattern to its
@@ -215,28 +270,28 @@
regex += '[^/]'
elif char == '[':
- # Braket expression wildcard. Except for the
beginning
- # exclamation mark, the whole braket expression
can be used
+ # Bracket expression wildcard. Except for the
beginning
+ # exclamation mark, the whole bracket
expression can be used
# directly as regex but we have to find where
the expression
# ends.
- # - "[][!]" matchs ']', '[' and '!'.
- # - "[]-]" matchs ']' and '-'.
- # - "[!]a-]" matchs any character except ']',
'a' and '-'.
+ # - "[][!]" matches ']', '[' and '!'.
+ # - "[]-]" matches ']' and '-'.
+ # - "[!]a-]" matches any character except ']',
'a' and '-'.
j = i
# Pass brack expression negation.
if j < end and pattern[j] == '!':
j += 1
- # Pass first closing braket if it is at the
beginning of the
+ # Pass first closing bracket if it is at the
beginning of the
# expression.
if j < end and pattern[j] == ']':
j += 1
- # Find closing braket. Stop once we reach the
end or find it.
+ # Find closing bracket. Stop once we reach the
end or find it.
while j < end and pattern[j] != ']':
j += 1
if j < end:
- # Found end of braket expression.
Increment j to be one past
- # the closing braket:
+ # Found end of bracket expression.
Increment j to be one past
+ # the closing bracket:
#
# [...]
# ^ ^
@@ -250,7 +305,7 @@
expr += '^'
i += 1
elif pattern[i] == '^':
- # POSIX declares that the regex
braket expression negation
+ # POSIX declares that the regex
bracket expression negation
# "[^...]" is undefined in a
glob pattern. Python's
# `fnmatch.translate()` escapes
the caret ('^') as a
# literal. To maintain
consistency with undefined behavior,
@@ -258,19 +313,19 @@
expr += '\\^'
i += 1
- # Build regex braket expression. Escape
slashes so they are
+ # Build regex bracket expression.
Escape slashes so they are
# treated as literal slashes by regex
as defined by POSIX.
expr += pattern[i:j].replace('\\',
'\\\\')
- # Add regex braket expression to regex
result.
+ # Add regex bracket expression to regex
result.
regex += expr
- # Set i to one past the closing braket.
+ # Set i to one past the closing bracket.
i = j
else:
- # Failed to find closing braket, treat
opening braket as a
- # braket literal instead of as an
expression.
+ # Failed to find closing bracket, treat
opening bracket as a
+ # bracket literal instead of as an
expression.
regex += '\\['
else:
@@ -281,18 +336,33 @@
@staticmethod
def escape(s):
+ # type: (AnyStr) -> AnyStr
"""
Escape special characters in the given string.
*s* (:class:`unicode` or :class:`bytes`) a filename or a string
that you want to escape, usually before adding it to a
`.gitignore`
- Returns the escaped string (:class:`unicode`, :class:`bytes`)
+ Returns the escaped string (:class:`unicode` or :class:`bytes`)
"""
+ if isinstance(s, unicode):
+ return_type = unicode
+ string = s
+ elif isinstance(s, bytes):
+ return_type = bytes
+ string = s.decode(_BYTES_ENCODING)
+ else:
+ raise TypeError("s:{!r} is not a unicode or byte
string.".format(s))
+
# Reference: https://git-scm.com/docs/gitignore#_pattern_format
meta_characters = r"[]!*#?"
- return "".join("\\" + x if x in meta_characters else x for x in
s)
+ out_string = "".join("\\" + x if x in meta_characters else x
for x in string)
+
+ if return_type is bytes:
+ return out_string.encode(_BYTES_ENCODING)
+ else:
+ return out_string
util.register_pattern('gitwildmatch', GitWildMatchPattern)
@@ -308,7 +378,7 @@
Warn about deprecation.
"""
self._deprecated()
- return super(GitIgnorePattern, self).__init__(*args, **kw)
+ super(GitIgnorePattern, self).__init__(*args, **kw)
@staticmethod
def _deprecated():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec/tests/test_gitwildmatch.py
new/pathspec-0.9.0/pathspec/tests/test_gitwildmatch.py
--- old/pathspec-0.8.1/pathspec/tests/test_gitwildmatch.py 2020-02-03
04:22:42.000000000 +0100
+++ new/pathspec-0.9.0/pathspec/tests/test_gitwildmatch.py 2021-07-18
02:15:39.000000000 +0200
@@ -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
@@ -184,6 +184,7 @@
This should match:
+ left/right
left/bar/right
left/foo/bar/right
left/bar/right/foo
@@ -198,12 +199,14 @@
pattern = GitWildMatchPattern(re.compile(regex), include)
results = set(pattern.match([
+ 'left/right',
'left/bar/right',
'left/foo/bar/right',
'left/bar/right/foo',
'foo/left/bar/right',
]))
self.assertEqual(results, {
+ 'left/right',
'left/bar/right',
'left/foo/bar/right',
'left/bar/right/foo',
@@ -223,6 +226,7 @@
This should match:
+ spam
foo/spam
foo/spam/bar
"""
@@ -232,14 +236,66 @@
pattern = GitWildMatchPattern(re.compile(regex), include)
results = set(pattern.match([
+ 'spam',
'foo/spam',
'foo/spam/bar',
]))
self.assertEqual(results, {
+ 'spam',
'foo/spam',
'foo/spam/bar',
})
+ def test_03_duplicate_leading_double_asterisk_edge_case(self):
+ """
+ Regression test for duplicate leading **/ bug.
+ """
+ regex, include = GitWildMatchPattern.pattern_to_regex('**')
+ self.assertTrue(include)
+ self.assertEqual(regex, '^.+$')
+
+ equivalent_regex, include =
GitWildMatchPattern.pattern_to_regex('**/**')
+ self.assertTrue(include)
+ self.assertEqual(equivalent_regex, regex)
+
+ equivalent_regex, include =
GitWildMatchPattern.pattern_to_regex('**/**/**')
+ self.assertTrue(include)
+ self.assertEqual(equivalent_regex, regex)
+
+ regex, include = GitWildMatchPattern.pattern_to_regex('**/api')
+ self.assertTrue(include)
+ self.assertEqual(regex, '^(?:.+/)?api(?:/.*)?$')
+
+ equivalent_regex, include =
GitWildMatchPattern.pattern_to_regex('**/**/api')
+ self.assertTrue(include)
+ self.assertEqual(equivalent_regex, regex)
+
+ regex, include = GitWildMatchPattern.pattern_to_regex('**/api/')
+ self.assertTrue(include)
+ self.assertEqual(regex, '^(?:.+/)?api/.*$')
+
+ equivalent_regex, include =
GitWildMatchPattern.pattern_to_regex('**/api/**')
+ self.assertTrue(include)
+ self.assertEqual(equivalent_regex, regex)
+
+ equivalent_regex, include =
GitWildMatchPattern.pattern_to_regex('**/**/api/**/**')
+ self.assertTrue(include)
+ self.assertEqual(equivalent_regex, regex)
+
+ def test_03_double_asterisk_trailing_slash_edge_case(self):
+ """
+ Tests the edge-case **/ pattern.
+
+ This should match everything except individual files in the
root directory.
+ """
+ regex, include = GitWildMatchPattern.pattern_to_regex('**/')
+ self.assertTrue(include)
+ self.assertEqual(regex, '^.+/.*$')
+
+ equivalent_regex, include =
GitWildMatchPattern.pattern_to_regex('**/**/')
+ self.assertTrue(include)
+ self.assertEqual(equivalent_regex, regex)
+
def test_04_infix_wildcard(self):
"""
Tests a pattern with an infix wildcard.
@@ -472,3 +528,21 @@
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)
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec/tests/test_pathspec.py
new/pathspec-0.9.0/pathspec/tests/test_pathspec.py
--- old/pathspec-0.8.1/pathspec/tests/test_pathspec.py 2020-11-07
20:27:35.000000000 +0100
+++ new/pathspec-0.9.0/pathspec/tests/test_pathspec.py 2021-06-12
18:27:25.000000000 +0200
@@ -13,6 +13,52 @@
The ``PathSpecTest`` class tests the ``PathSpec`` class.
"""
+ def test_01_absolute_dir_paths_1(self):
+ """
+ Tests that absolute paths will be properly normalized and
matched.
+ """
+ spec = pathspec.PathSpec.from_lines('gitwildmatch', [
+ 'foo',
+ ])
+ results = set(spec.match_files([
+ '/a.py',
+ '/foo/a.py',
+ '/x/a.py',
+ '/x/foo/a.py',
+ 'a.py',
+ 'foo/a.py',
+ 'x/a.py',
+ 'x/foo/a.py',
+ ]))
+ self.assertEqual(results, {
+ '/foo/a.py',
+ '/x/foo/a.py',
+ 'foo/a.py',
+ 'x/foo/a.py',
+ })
+
+ def test_01_absolute_dir_paths_2(self):
+ """
+ Tests that absolute paths will be properly normalized and
matched.
+ """
+ spec = pathspec.PathSpec.from_lines('gitwildmatch', [
+ '/foo',
+ ])
+ results = set(spec.match_files([
+ '/a.py',
+ '/foo/a.py',
+ '/x/a.py',
+ '/x/foo/a.py',
+ 'a.py',
+ 'foo/a.py',
+ 'x/a.py',
+ 'x/foo/a.py',
+ ]))
+ self.assertEqual(results, {
+ '/foo/a.py',
+ 'foo/a.py',
+ })
+
def test_01_current_dir_paths(self):
"""
Tests that paths referencing the current directory will be
properly
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec/util.py
new/pathspec-0.9.0/pathspec/util.py
--- old/pathspec-0.8.1/pathspec/util.py 2020-04-07 05:43:06.000000000 +0200
+++ new/pathspec-0.9.0/pathspec/util.py 2021-06-12 19:28:58.000000000 +0200
@@ -7,8 +7,35 @@
import os.path
import posixpath
import stat
-
-from .compat import Collection, Iterable, string_types, unicode
+try:
+ from typing import (
+ Any,
+ AnyStr,
+ Callable,
+ Dict,
+ Iterable,
+ Iterator,
+ List,
+ Optional,
+ Sequence,
+ Set,
+ Text,
+ Union)
+except ImportError:
+ pass
+try:
+ # Python 3.6+ type hints.
+ from os import PathLike
+ from typing import Collection
+except ImportError:
+ pass
+
+from .compat import (
+ CollectionType,
+ IterableType,
+ string_types,
+ unicode)
+from .pattern import Pattern
NORMALIZE_PATH_SEPS = [sep for sep in [os.sep, os.altsep] if sep and sep !=
posixpath.sep]
"""
@@ -26,6 +53,7 @@
def detailed_match_files(patterns, files, all_matches=None):
+ # type: (Iterable[Pattern], Iterable[Text], Optional[bool]) ->
Dict[Text, 'MatchDetail']
"""
Matches the files to the patterns, and returns which patterns matched
the files.
@@ -43,7 +71,7 @@
Returns the matched files (:class:`dict`) which maps each matched file
(:class:`str`) to the patterns that matched in order
(:class:`.MatchDetail`).
"""
- all_files = files if isinstance(files, Collection) else list(files)
+ all_files = files if isinstance(files, CollectionType) else list(files)
return_files = {}
for pattern in patterns:
if pattern.include is not None:
@@ -68,6 +96,7 @@
def _is_iterable(value):
+ # type: (Any) -> bool
"""
Check whether the value is an iterable (excludes strings).
@@ -75,10 +104,11 @@
Returns whether *value* is a iterable (:class:`bool`).
"""
- return isinstance(value, Iterable) and not isinstance(value, (unicode,
bytes))
+ return isinstance(value, IterableType) and not isinstance(value,
(unicode, bytes))
def iter_tree_entries(root, on_error=None, follow_links=None):
+ # type: (Text, Optional[Callable], Optional[bool]) ->
Iterator['TreeEntry']
"""
Walks the specified directory for all files and directories.
@@ -96,7 +126,7 @@
Raises :exc:`RecursionError` if recursion is detected.
- Returns an :class:`~collections.abc.Iterable` yielding each file or
+ Returns an :class:`~collections.abc.Iterator` yielding each file or
directory entry (:class:`.TreeEntry`) relative to *root*.
"""
if on_error is not None and not callable(on_error):
@@ -110,6 +140,7 @@
def iter_tree_files(root, on_error=None, follow_links=None):
+ # type: (Text, Optional[Callable], Optional[bool]) -> Iterator[Text]
"""
Walks the specified directory for all files.
@@ -127,7 +158,7 @@
Raises :exc:`RecursionError` if recursion is detected.
- Returns an :class:`~collections.abc.Iterable` yielding the path to
+ Returns an :class:`~collections.abc.Iterator` yielding the path to
each file (:class:`str`) relative to *root*.
"""
if on_error is not None and not callable(on_error):
@@ -146,6 +177,7 @@
def _iter_tree_entries_next(root_full, dir_rel, memo, on_error, follow_links):
+ # type: (Text, Text, Dict[Text, Text], Callable, bool) ->
Iterator['TreeEntry']
"""
Scan the directory for all descendant files.
@@ -223,6 +255,7 @@
def lookup_pattern(name):
+ # type: (Text) -> Callable[[AnyStr], Pattern]
"""
Lookups a registered pattern factory by name.
@@ -235,6 +268,7 @@
def match_file(patterns, file):
+ # type: (Iterable[Pattern], Text) -> bool
"""
Matches the file to the patterns.
@@ -255,6 +289,7 @@
def match_files(patterns, files):
+ # type: (Iterable[Pattern], Iterable[Text]) -> Set[Text]
"""
Matches the files to the patterns.
@@ -266,7 +301,7 @@
Returns the matched files (:class:`set` of :class:`str`).
"""
- all_files = files if isinstance(files, Collection) else list(files)
+ all_files = files if isinstance(files, CollectionType) else list(files)
return_files = set()
for pattern in patterns:
if pattern.include is not None:
@@ -279,6 +314,7 @@
def _normalize_entries(entries, separators=None):
+ # type: (Iterable['TreeEntry'], Optional[Collection[Text]]) ->
Dict[Text, 'TreeEntry']
"""
Normalizes the entry paths to use the POSIX path separator.
@@ -299,8 +335,10 @@
def normalize_file(file, separators=None):
+ # type: (Union[Text, PathLike], Optional[Collection[Text]]) -> Text
"""
- Normalizes the file path to use the POSIX path separator (i.e.,
``'/'``).
+ Normalizes the file path to use the POSIX path separator (i.e.,
+ ``'/'``), and make the paths relative (remove leading ``'/'``).
*file* (:class:`str` or :class:`pathlib.PurePath`) is the file path.
@@ -323,14 +361,19 @@
for sep in separators:
norm_file = norm_file.replace(sep, posixpath.sep)
- # Remove current directory prefix.
- if norm_file.startswith('./'):
+ if norm_file.startswith('/'):
+ # Make path relative.
+ norm_file = norm_file[1:]
+
+ elif norm_file.startswith('./'):
+ # Remove current directory prefix.
norm_file = norm_file[2:]
return norm_file
def normalize_files(files, separators=None):
+ # type: (Iterable[Union[str, PathLike]], Optional[Collection[Text]]) ->
Dict[Text, List[Union[str, PathLike]]]
"""
Normalizes the file paths to use the POSIX path separator.
@@ -341,16 +384,23 @@
:data:`None`) optionally contains the path separators to normalize.
See :func:`normalize_file` for more information.
- Returns a :class:`dict` mapping the each normalized file path
(:class:`str`)
- to the original file path (:class:`str`)
+ Returns a :class:`dict` mapping the each normalized file path
+ (:class:`str`) to the original file paths (:class:`list` of
+ :class:`str` or :class:`pathlib.PurePath`).
"""
norm_files = {}
for path in files:
- norm_files[normalize_file(path, separators=separators)] = path
+ norm_file = normalize_file(path, separators=separators)
+ if norm_file in norm_files:
+ norm_files[norm_file].append(path)
+ else:
+ norm_files[norm_file] = [path]
+
return norm_files
def register_pattern(name, pattern_factory, override=None):
+ # type: (Text, Callable[[AnyStr], Pattern], Optional[bool]) -> None
"""
Registers the specified pattern factory.
@@ -382,6 +432,7 @@
"""
def __init__(self, name, pattern_factory):
+ # type: (Text, Callable[[AnyStr], Pattern]) -> None
"""
Initializes the :exc:`AlreadyRegisteredError` instance.
@@ -394,6 +445,7 @@
@property
def message(self):
+ # type: () -> Text
"""
*message* (:class:`str`) is the error message.
"""
@@ -404,6 +456,7 @@
@property
def name(self):
+ # type: () -> Text
"""
*name* (:class:`str`) is the name of the registered pattern.
"""
@@ -411,6 +464,7 @@
@property
def pattern_factory(self):
+ # type: () -> Callable[[AnyStr], Pattern]
"""
*pattern_factory* (:class:`~collections.abc.Callable`) is the
registered pattern factory.
@@ -425,6 +479,7 @@
"""
def __init__(self, real_path, first_path, second_path):
+ # type: (Text, Text, Text) -> None
"""
Initializes the :exc:`RecursionError` instance.
@@ -441,6 +496,7 @@
@property
def first_path(self):
+ # type: () -> Text
"""
*first_path* (:class:`str`) is the first path encountered for
:attr:`self.real_path <RecursionError.real_path>`.
@@ -449,6 +505,7 @@
@property
def message(self):
+ # type: () -> Text
"""
*message* (:class:`str`) is the error message.
"""
@@ -460,6 +517,7 @@
@property
def real_path(self):
+ # type: () -> Text
"""
*real_path* (:class:`str`) is the real path that recursion was
encountered on.
@@ -468,6 +526,7 @@
@property
def second_path(self):
+ # type: () -> Text
"""
*second_path* (:class:`str`) is the second path encountered for
:attr:`self.real_path <RecursionError.real_path>`.
@@ -484,6 +543,7 @@
__slots__ = ('patterns',)
def __init__(self, patterns):
+ # type: (Sequence[Pattern]) -> None
"""
Initialize the :class:`.MatchDetail` instance.
@@ -510,6 +570,7 @@
__slots__ = ('_lstat', 'name', 'path', '_stat')
def __init__(self, name, path, lstat, stat):
+ # type: (Text, Text, os.stat_result, os.stat_result) -> None
"""
Initialize the :class:`.TreeEntry` instance.
@@ -547,6 +608,7 @@
"""
def is_dir(self, follow_links=None):
+ # type: (Optional[bool]) -> bool
"""
Get whether the entry is a directory.
@@ -563,6 +625,7 @@
return stat.S_ISDIR(node_stat.st_mode)
def is_file(self, follow_links=None):
+ # type: (Optional[bool]) -> bool
"""
Get whether the entry is a regular file.
@@ -579,12 +642,14 @@
return stat.S_ISREG(node_stat.st_mode)
def is_symlink(self):
+ # type: () -> bool
"""
Returns whether the entry is a symbolic link (:class:`bool`).
"""
return stat.S_ISLNK(self._lstat.st_mode)
def stat(self, follow_links=None):
+ # type: (Optional[bool]) -> os.stat_result
"""
Get the cached stat result for the entry.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec.egg-info/PKG-INFO
new/pathspec-0.9.0/pathspec.egg-info/PKG-INFO
--- old/pathspec-0.8.1/pathspec.egg-info/PKG-INFO 2020-11-07
20:37:54.000000000 +0100
+++ new/pathspec-0.9.0/pathspec.egg-info/PKG-INFO 2021-07-18
02:27:56.000000000 +0200
@@ -1,12 +1,13 @@
-Metadata-Version: 1.2
+Metadata-Version: 2.1
Name: pathspec
-Version: 0.8.1
+Version: 0.9.0
Summary: Utility library for gitignore style pattern matching of file paths.
Home-page: https://github.com/cpburnz/python-path-specification
Author: Caleb P. Burns
Author-email: [email protected]
License: MPL 2.0
-Description: *pathspec*: Path Specification
+Description:
+ *pathspec*: Path Specification
==============================
*pathspec* is a utility library for pattern matching of file paths. So
@@ -159,9 +160,25 @@
.. _`Ruby gem`: https://github.com/highb/pathspec-ruby
+
Change History
==============
+ 0.9.0 (2021-07-17)
+ ------------------
+
+ - `Issue #44`_/`Issue #50`_: Raise `GitWildMatchPatternError` for
invalid git patterns.
+ - `Issue #45`_: Fix for duplicate leading double-asterisk, and edge
cases.
+ - `Issue #46`_: Fix matching absolute paths.
+ - API change: `util.normalize_files()` now returns a `Dict[str,
List[pathlike]]` instead of a `Dict[str, pathlike]`.
+ - Added type hinting.
+
+ .. _`Issue #44`:
https://github.com/cpburnz/python-path-specification/issues/44
+ .. _`Issue #45`:
https://github.com/cpburnz/python-path-specification/pull/45
+ .. _`Issue #46`:
https://github.com/cpburnz/python-path-specification/issues/46
+ .. _`Issue #50`:
https://github.com/cpburnz/python-path-specification/pull/50
+
+
0.8.1 (2020-11-07)
------------------
@@ -369,6 +386,7 @@
------------------
- Initial release.
+
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
@@ -382,8 +400,10 @@
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
-Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
+Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
+Description-Content-Type: text/x-rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec.egg-info/SOURCES.txt
new/pathspec-0.9.0/pathspec.egg-info/SOURCES.txt
--- old/pathspec-0.8.1/pathspec.egg-info/SOURCES.txt 2020-11-07
20:37:54.000000000 +0100
+++ new/pathspec-0.9.0/pathspec.egg-info/SOURCES.txt 2021-07-18
02:27:56.000000000 +0200
@@ -2,9 +2,12 @@
LICENSE
MANIFEST.in
README.rst
+pathspec_meta.py
setup.cfg
setup.py
+tox_pip_install.py
pathspec/__init__.py
+pathspec/_meta.py
pathspec/compat.py
pathspec/pathspec.py
pathspec/pattern.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/pathspec_meta.py
new/pathspec-0.9.0/pathspec_meta.py
--- old/pathspec-0.8.1/pathspec_meta.py 1970-01-01 01:00:00.000000000 +0100
+++ new/pathspec-0.9.0/pathspec_meta.py 2021-07-18 02:13:02.000000000 +0200
@@ -0,0 +1,43 @@
+# encoding: utf-8
+"""
+This module contains the project meta-data.
+"""
+
+__author__ = "Caleb P. Burns"
+__copyright__ = "Copyright ?? 2013-2021 Caleb P. Burns"
+__credits__ = [
+ "dahlia <https://github.com/dahlia>",
+ "highb <https://github.com/highb>",
+ "029xue <https://github.com/029xue>",
+ "mikexstudios <https://github.com/mikexstudios>",
+ "nhumrich <https://github.com/nhumrich>",
+ "davidfraser <https://github.com/davidfraser>",
+ "demurgos <https://github.com/demurgos>",
+ "ghickman <https://github.com/ghickman>",
+ "nvie <https://github.com/nvie>",
+ "adrienverge <https://github.com/adrienverge>",
+ "AndersBlomdell <https://github.com/AndersBlomdell>",
+ "highb <https://github.com/highb>",
+ "thmxv <https://github.com/thmxv>",
+ "wimglenn <https://github.com/wimglenn>",
+ "hugovk <https://github.com/hugovk>",
+ "dcecile <https://github.com/dcecile>",
+ "mroutis <https://github.com/mroutis>",
+ "jdufresne <https://github.com/jdufresne>",
+ "groodt <https://github.com/groodt>",
+ "ftrofin <https://github.com/ftrofin>",
+ "pykong <https://github.com/pykong>",
+ "nhhollander <https://github.com/nhhollander>",
+ "KOLANICH <https://github.com/KOLANICH>",
+ "JonjonHays <https://github.com/JonjonHays>",
+ "Isaac0616 <https://github.com/Isaac0616>",
+ "SebastiaanZ <https://github.com/SebastiaanZ>",
+ "RoelAdriaans <https://github.com/RoelAdriaans>",
+ "raviselker <https://github.com/raviselker>",
+ "johanvergeer <https://github.com/johanvergeer>",
+ "danjer <https://github.com/danjer>",
+ "jhbuhrman <https://github.com/jhbuhrman>",
+ "WPDOrdina <https://github.com/WPDOrdina>",
+]
+__license__ = "MPL 2.0"
+__version__ = "0.9.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/setup.cfg new/pathspec-0.9.0/setup.cfg
--- old/pathspec-0.8.1/setup.cfg 2020-11-07 20:37:55.000000000 +0100
+++ new/pathspec-0.9.0/setup.cfg 2021-07-18 02:27:56.000000000 +0200
@@ -1,3 +1,38 @@
+[metadata]
+author = Caleb P. Burns
+author_email = [email protected]
+classifiers =
+ Development Status :: 4 - Beta
+ Intended Audience :: Developers
+ License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
+ Operating System :: OS Independent
+ Programming Language :: Python
+ Programming Language :: Python :: 2
+ Programming Language :: Python :: 2.7
+ Programming Language :: Python :: 3
+ Programming Language :: Python :: 3.5
+ Programming Language :: Python :: 3.6
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ Programming Language :: Python :: Implementation :: CPython
+ Programming Language :: Python :: Implementation :: PyPy
+ Topic :: Software Development :: Libraries :: Python Modules
+ Topic :: Utilities
+description = Utility library for gitignore style pattern matching of file
paths.
+license = MPL 2.0
+long_description = file: README.rst, CHANGES.rst
+long_description_content_type = text/x-rst
+name = pathspec
+version = attr: pathspec_meta.__version__
+url = https://github.com/cpburnz/python-path-specification
+
+[options]
+packages = find:
+python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
+setup_requires = setuptools >=39.2.0
+test_suite = pathspec.tests
+
[bdist_wheel]
universal = 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/setup.py new/pathspec-0.9.0/setup.py
--- old/pathspec-0.8.1/setup.py 2020-01-29 03:45:39.000000000 +0100
+++ new/pathspec-0.9.0/setup.py 2021-06-03 05:48:54.000000000 +0200
@@ -1,44 +1,5 @@
# encoding: utf-8
-import io
-from setuptools import setup, find_packages
+from setuptools import setup
-from pathspec import __author__, __email__, __license__, __project__,
__version__
-
-# Read readme and changes files.
-with io.open("README.rst", mode='r', encoding='UTF-8') as fh:
- readme = fh.read().strip()
-with io.open("CHANGES.rst", mode='r', encoding='UTF-8') as fh:
- changes = fh.read().strip()
-
-setup(
- name=__project__,
- version=__version__,
- author=__author__,
- author_email=__email__,
- url="https://github.com/cpburnz/python-path-specification",
- description="Utility library for gitignore style pattern matching of
file paths.",
- long_description=readme + "\n\n" + changes,
- python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
- classifiers=[
- "Development Status :: 4 - Beta",
- "Intended Audience :: Developers",
- "License :: OSI Approved :: Mozilla Public License 2.0 (MPL
2.0)",
- "Operating System :: OS Independent",
- "Programming Language :: Python",
- "Programming Language :: Python :: 2",
- "Programming Language :: Python :: 2.7",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.5",
- "Programming Language :: Python :: 3.6",
- "Programming Language :: Python :: 3.7",
- "Programming Language :: Python :: 3.8",
- "Programming Language :: Python :: Implementation :: CPython",
- "Programming Language :: Python :: Implementation :: PyPy",
- "Topic :: Software Development :: Libraries :: Python Modules",
- "Topic :: Utilities",
- ],
- license=__license__,
- packages=find_packages(),
- test_suite='pathspec.tests',
-)
+setup()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pathspec-0.8.1/tox_pip_install.py
new/pathspec-0.9.0/tox_pip_install.py
--- old/pathspec-0.8.1/tox_pip_install.py 1970-01-01 01:00:00.000000000
+0100
+++ new/pathspec-0.9.0/tox_pip_install.py 2021-06-03 05:48:54.000000000
+0200
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# This file is part of packagename <https://github.com/kevinoid/packagename>
+# Made available under CC0 1.0 Universal, see LICENSE.txt
+# Copyright 2019-2020 Kevin Locke <[email protected]>
+"""
+Script to reinstall pip before running `pip install`.
+
+Workaround for https://bugs.debian.org/962654
+"""
+
+import os
+import sys
+
+# Must be invoked with pip package (optionally version-constrained) as first
+# argument, install options+packages as subsequent options.
+if len(sys.argv) < 3 or not sys.argv[1].startswith('pip'):
+ sys.stderr.write(
+ 'Usage: ' + sys.argv[0] + ' <pip version> [options] <packages...>\n'
+ )
+ sys.exit(1)
+
+# Workaround is only needed on Debian (and derivatives)
+if os.path.exists('/etc/debian_version'):
+ pip_exit_code = os.spawnl(
+ os.P_WAIT,
+ sys.executable,
+ sys.executable,
+ '-m',
+ 'pip',
+ 'install',
+ '--force-reinstall',
+ '--no-compile',
+ sys.argv[1],
+ )
+ if pip_exit_code != 0:
+ sys.exit(pip_exit_code)
+
+os.execv(
+ sys.executable, [sys.executable, '-m', 'pip', 'install'] + sys.argv[2:]
+)