Skip to content

Commit a599470

Browse files
committed
Raise more specific exceptions for GIT_EEXISTS and GIT_EINVALIDSPEC
Before, both would raise ValueError, making it hard to distinguish between them to show users a meaningful error message. The new exceptions AlreadyExistsError and InvalidSpecError extend ValueError, so this change should be backwards-compatible.
1 parent e70c785 commit a599470

File tree

4 files changed

+41
-5
lines changed

4 files changed

+41
-5
lines changed

docs/general.rst

+13
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,16 @@ Exceptions
5959
:show-inheritance:
6060
:undoc-members:
6161

62+
.. autoexception:: pygit2.AlreadyExistsError
63+
:members:
64+
:show-inheritance:
65+
:undoc-members:
66+
67+
Exception when trying to create an object (reference, etc) that already exists.
68+
69+
.. autoexception:: pygit2.InvalidSpecError
70+
:members:
71+
:show-inheritance:
72+
:undoc-members:
73+
74+
Exception when an input specification such as a reference name is invalid.

src/error.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "error.h"
2929

3030
PyObject *GitError;
31+
PyObject *AlreadyExistsError;
32+
PyObject *InvalidSpecError;
3133

3234
PyObject *
3335
Error_type(int type)
@@ -41,7 +43,7 @@ Error_type(int type)
4143

4244
/* A reference with this name already exists */
4345
case GIT_EEXISTS:
44-
return PyExc_ValueError;
46+
return AlreadyExistsError;
4547

4648
/* The given short oid is ambiguous */
4749
case GIT_EAMBIGUOUS:
@@ -53,7 +55,7 @@ Error_type(int type)
5355

5456
/* Invalid input spec */
5557
case GIT_EINVALIDSPEC:
56-
return PyExc_ValueError;
58+
return InvalidSpecError;
5759

5860
/* Skip and passthrough the given ODB backend */
5961
case GIT_PASSTHROUGH:

src/pygit2.c

+10
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#include "options.h"
3838

3939
extern PyObject *GitError;
40+
extern PyObject *AlreadyExistsError;
41+
extern PyObject *InvalidSpecError;
4042

4143
extern PyTypeObject RepositoryType;
4244
extern PyTypeObject OidType;
@@ -245,6 +247,14 @@ moduleinit(PyObject* m)
245247
Py_INCREF(GitError);
246248
PyModule_AddObject(m, "GitError", GitError);
247249

250+
AlreadyExistsError = PyErr_NewException("_pygit2.AlreadyExistsError", PyExc_ValueError, NULL);
251+
Py_INCREF(AlreadyExistsError);
252+
PyModule_AddObject(m, "AlreadyExistsError", AlreadyExistsError);
253+
254+
InvalidSpecError = PyErr_NewException("_pygit2.InvalidSpecError", PyExc_ValueError, NULL);
255+
Py_INCREF(InvalidSpecError);
256+
PyModule_AddObject(m, "InvalidSpecError", InvalidSpecError);
257+
248258
/* Repository */
249259
INIT_TYPE(RepositoryType, NULL, PyType_GenericNew)
250260
ADD_TYPE(m, Repository)

test/test_refs.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@
3232

3333
import pytest
3434

35-
from pygit2 import GitError, GIT_REF_OID, GIT_REF_SYMBOLIC, Signature
35+
from pygit2 import GIT_REF_OID, GIT_REF_SYMBOLIC, Signature
3636
from pygit2 import Commit, Tree, reference_is_valid_name
37+
from pygit2 import AlreadyExistsError, GitError, InvalidSpecError
3738
from . import utils
3839

3940
LAST_COMMIT = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98'
@@ -376,8 +377,9 @@ def test_create_reference(self):
376377
assert reference.target.hex == LAST_COMMIT
377378

378379
# try to create existing reference
379-
with pytest.raises(ValueError):
380+
with pytest.raises(AlreadyExistsError) as error:
380381
self.repo.create_reference('refs/tags/version1', LAST_COMMIT)
382+
assert isinstance(error.value, ValueError)
381383

382384
# try to create existing reference with force
383385
reference = self.repo.create_reference('refs/tags/version1',
@@ -394,15 +396,24 @@ def test_create_symbolic_reference(self):
394396
assert reference.target == 'refs/heads/master'
395397

396398
# try to create existing symbolic reference
397-
with pytest.raises(ValueError):
399+
with pytest.raises(AlreadyExistsError) as error:
398400
repo.create_reference('refs/tags/beta', 'refs/heads/master')
401+
assert isinstance(error.value, ValueError)
399402

400403
# try to create existing symbolic reference with force
401404
reference = repo.create_reference('refs/tags/beta',
402405
'refs/heads/master', force=True)
403406
assert reference.type == GIT_REF_SYMBOLIC
404407
assert reference.target == 'refs/heads/master'
405408

409+
def test_create_invalid_reference(self):
410+
repo = self.repo
411+
412+
# try to create a reference with an invalid name
413+
with pytest.raises(InvalidSpecError) as error:
414+
repo.create_reference('refs/tags/in..valid', 'refs/heads/master')
415+
assert isinstance(error.value, ValueError)
416+
406417
# def test_packall_references(self):
407418
# self.repo.packall_references()
408419

0 commit comments

Comments
 (0)