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 <dmuel...@suse.com>
+
+- 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: cpbu...@gmail.com
 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__ = "cpbu...@gmail.com"
-__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: cpbu...@gmail.com
 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 = cpbu...@gmail.com
+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 <ke...@kevinlocke.name>
+"""
+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:]
+)

Reply via email to