Repository: gitpython-developers/GitPython
Pull request #620 (2017-04-17 11:14:53)

Add base class for package exceptions.
This can help shorten client code when all git exceptions are to be processed in one block.


Patch:
diff --git a/AUTHORS b/AUTHORS
index bf0f5e05..781695ba 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -17,5 +17,6 @@ Contributors are:
 -Phil Elson <pelson _dot_ pub _at_ gmail.com>
 -Bernard `Guyzmo` Pratz <guyzmo+gitpython+pub@m0g.net>
 -Timothy B. Hartman <tbhartman _at_ gmail.com>
+-Konstantin Popov <konstantin.popov.89 _at_ yandex.ru>
 
 Portions derived from other open source works and are clearly marked.
diff --git a/git/exc.py b/git/exc.py
index 69ecc1d0..a737110c 100644
--- a/git/exc.py
+++ b/git/exc.py
@@ -9,7 +9,11 @@ from gitdb.exc import *     # NOQA @UnusedWildImport
 from git.compat import UnicodeMixin, safe_decode, string_types
 
 
-class InvalidGitRepositoryError(Exception):
+class GitError(Exception):
+    """ Base class for all package exceptions """
+
+
+class InvalidGitRepositoryError(GitError):
     """ Thrown if the given repository appears to have an invalid format.  """
 
 
@@ -17,11 +21,11 @@ class WorkTreeRepositoryUnsupported(InvalidGitRepositoryError):
     """ Thrown to indicate we can't handle work tree repositories """
 
 
-class NoSuchPathError(OSError):
+class NoSuchPathError(GitError, OSError):
     """ Thrown if a path could not be access by the system. """
 
 
-class CommandError(UnicodeMixin, Exception):
+class CommandError(UnicodeMixin, GitError):
     """Base class for exceptions thrown at every stage of `Popen()` execution.
 
     :param command:
@@ -74,7 +78,7 @@ class GitCommandError(CommandError):
         super(GitCommandError, self).__init__(command, status, stderr, stdout)
 
 
-class CheckoutError(Exception):
+class CheckoutError(GitError):
     """Thrown if a file could not be checked out from the index as it contained
     changes.
 
@@ -98,7 +102,7 @@ class CheckoutError(Exception):
         return Exception.__str__(self) + ":%s" % self.failed_files
 
 
-class CacheError(Exception):
+class CacheError(GitError):
 
     """Base for all errors related to the git index, which is called cache internally"""
 
@@ -117,7 +121,7 @@ class HookExecutionError(CommandError):
         self._msg = u"Hook('%s') failed%s"
 
 
-class RepositoryDirtyError(Exception):
+class RepositoryDirtyError(GitError):
     """Thrown whenever an operation on a repository fails as it has uncommitted changes that would be overwritten"""
 
     def __init__(self, repo, message):
diff --git a/git/remote.py b/git/remote.py
index 60319ce1..fd76e592 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -212,11 +212,16 @@ class FetchInfo(object):
 
     _flag_map = {'!': ERROR,
                  '+': FORCED_UPDATE,
-                 '-': TAG_UPDATE,
                  '*': 0,
                  '=': HEAD_UPTODATE,
                  ' ': FAST_FORWARD}
 
+    v = Git().version_info[:2]
+    if v >= (2, 10):
+        _flag_map['t'] = TAG_UPDATE
+    else:
+        _flag_map['-'] = TAG_UPDATE
+
     def __init__(self, ref, flags, note='', old_commit=None, remote_ref_path=None):
         """
         Initialize a new instance
@@ -629,7 +634,7 @@ class Remote(LazyMixin, Iterable):
         fetch_info_lines = list()
         # Basically we want all fetch info lines which appear to be in regular form, and thus have a
         # command character. Everything else we ignore,
-        cmds = set(PushInfo._flag_map.keys()) & set(FetchInfo._flag_map.keys())
+        cmds = set(FetchInfo._flag_map.keys())
 
         progress_handler = progress.new_message_handler()
         handle_process_output(proc, None, progress_handler, finalizer=None, decode_streams=False)


Test patch:
diff --git a/git/test/test_exc.py b/git/test/test_exc.py
index 33f44034..28d824d0 100644
--- a/git/test/test_exc.py
+++ b/git/test/test_exc.py
@@ -10,10 +10,17 @@ import re
 
 import ddt
 from git.exc import (
+    InvalidGitRepositoryError,
+    WorkTreeRepositoryUnsupported,
+    NoSuchPathError,
     CommandError,
     GitCommandNotFound,
     GitCommandError,
+    CheckoutError,
+    CacheError,
+    UnmergedEntriesError,
     HookExecutionError,
+    RepositoryDirtyError,
 )
 from git.test.lib import TestBase
 
@@ -44,6 +51,26 @@ _streams_n_substrings = (None, 'steram', 'ομορφο stream', )
 @ddt.ddt
 class TExc(TestBase):
 
+    def test_ExceptionsHaveBaseClass(self):
+        from git.exc import GitError
+        self.assertIsInstance(GitError(), Exception)
+        
+        exception_classes = [
+            InvalidGitRepositoryError,
+            WorkTreeRepositoryUnsupported,
+            NoSuchPathError,
+            CommandError,
+            GitCommandNotFound,
+            GitCommandError,
+            CheckoutError,
+            CacheError,
+            UnmergedEntriesError,
+            HookExecutionError,
+            RepositoryDirtyError,
+        ]
+        for ex_class in exception_classes:
+            self.assertTrue(issubclass(ex_class, GitError))
+
     @ddt.data(*list(itt.product(_cmd_argvs, _causes_n_substrings, _streams_n_substrings)))
     def test_CommandError_unicode(self, case):
         argv, (cause, subs), stream = case