Skip to content

Commit f74a211

Browse files
committed
oid: now only accept Oid or hex, not raw
Every method that takes an oid has changed what it accepts. Before it was (in both Python 2 and 3): - An Oid object - An hex oid, represented as a unicode string - A raw oid, represented as a bytes string Now the behaviour is different between Python 2 and 3. Now in Python 2 we take: - An Oid object - An hex oid, represented as a bytes or unicode string Now in Python 3 we take: - An Oid object - An hex oid, represented as a unicode string We have dropt direct support for raw strings. To use a raw string first build an Oid object: oid = Oid(raw=raw) We have also dropt support for short raw oids. The Oid constructor takes full oids, if passed short oids the behavior is undefined.
1 parent 571fe8a commit f74a211

File tree

3 files changed

+79
-47
lines changed

3 files changed

+79
-47
lines changed

src/oid.c

Lines changed: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -45,63 +45,71 @@ git_oid_to_python(const git_oid *oid)
4545
return (PyObject*)py_oid;
4646
}
4747

48-
4948
int
50-
py_str_to_git_oid(PyObject *py_str, git_oid *oid)
49+
_oid_from_hex(PyObject *py_oid, git_oid *oid)
5150
{
5251
PyObject *py_hex;
53-
char *hex_or_bin;
5452
int err;
53+
char *hex;
5554
Py_ssize_t len;
5655

57-
/* Case 1: Git Oid */
58-
if (PyObject_TypeCheck(py_str, (PyTypeObject*)&OidType)) {
59-
git_oid_cpy(oid, &((Oid*)py_str)->oid);
60-
return GIT_OID_RAWSZ;
61-
}
62-
63-
/* Case 2: raw sha (bytes) */
64-
if (PyBytes_Check(py_str)) {
65-
err = PyBytes_AsStringAndSize(py_str, &hex_or_bin, &len);
56+
#if PY_MAJOR_VERSION == 2
57+
/* Bytes (only supported in Python 2) */
58+
if (PyBytes_Check(py_oid)) {
59+
err = PyBytes_AsStringAndSize(py_oid, &hex, &len);
6660
if (err)
6761
return -1;
68-
if (len > GIT_OID_RAWSZ) {
69-
PyErr_SetObject(PyExc_ValueError, py_str);
62+
63+
err = git_oid_fromstrn(oid, hex, len);
64+
if (err < 0) {
65+
PyErr_SetObject(Error_type(err), py_oid);
7066
return -1;
7167
}
72-
memcpy(oid->id, (const unsigned char*)hex_or_bin, len);
73-
return len * 2;
68+
69+
return len;
7470
}
71+
#endif
7572

76-
/* Case 3: hex sha (unicode) */
77-
if (PyUnicode_Check(py_str)) {
78-
py_hex = PyUnicode_AsASCIIString(py_str);
73+
/* Unicode */
74+
if (PyUnicode_Check(py_oid)) {
75+
py_hex = PyUnicode_AsASCIIString(py_oid);
7976
if (py_hex == NULL)
8077
return -1;
81-
err = PyBytes_AsStringAndSize(py_hex, &hex_or_bin, &len);
78+
79+
err = PyBytes_AsStringAndSize(py_hex, &hex, &len);
8280
if (err) {
8381
Py_DECREF(py_hex);
8482
return -1;
8583
}
8684

87-
err = git_oid_fromstrn(oid, hex_or_bin, len);
88-
85+
err = git_oid_fromstrn(oid, hex, len);
8986
Py_DECREF(py_hex);
90-
9187
if (err < 0) {
92-
PyErr_SetObject(Error_type(err), py_str);
88+
PyErr_SetObject(Error_type(err), py_oid);
9389
return -1;
9490
}
91+
9592
return len;
9693
}
9794

9895
/* Type error */
99-
PyErr_Format(PyExc_TypeError,
100-
"Git object id must be byte or a text string, not: %.200s",
101-
Py_TYPE(py_str)->tp_name);
96+
PyErr_SetObject(PyExc_TypeError, py_oid);
10297
return -1;
10398
}
10499

100+
int
101+
py_str_to_git_oid(PyObject *py_oid, git_oid *oid)
102+
{
103+
/* Oid */
104+
if (PyObject_TypeCheck(py_oid, (PyTypeObject*)&OidType)) {
105+
git_oid_cpy(oid, &((Oid*)py_oid)->oid);
106+
return GIT_OID_RAWSZ;
107+
}
108+
109+
/* Hex */
110+
return _oid_from_hex(py_oid, oid);
111+
}
112+
105113
int
106114
py_str_to_git_oid_expand(git_repository *repo, PyObject *py_str, git_oid *oid)
107115
{
@@ -152,6 +160,8 @@ Oid_init(Oid *self, PyObject *args, PyObject *kw)
152160
char *keywords[] = {"raw", "hex", NULL};
153161
PyObject *raw = NULL, *hex = NULL;
154162
int err;
163+
char *bytes;
164+
Py_ssize_t len;
155165

156166
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OO", keywords, &raw, &hex))
157167
return -1;
@@ -166,12 +176,23 @@ Oid_init(Oid *self, PyObject *args, PyObject *kw)
166176
return -1;
167177
}
168178

169-
/* Get the oid. */
170-
if (raw != NULL)
171-
err = py_str_to_git_oid(raw, &self->oid);
172-
else
173-
err = py_str_to_git_oid(hex, &self->oid);
179+
/* Case 1: raw */
180+
if (raw != NULL) {
181+
err = PyBytes_AsStringAndSize(raw, &bytes, &len);
182+
if (err)
183+
return -1;
184+
185+
if (len > GIT_OID_RAWSZ) {
186+
PyErr_SetObject(PyExc_ValueError, raw);
187+
return -1;
188+
}
189+
190+
memcpy(self->oid.id, (const unsigned char*)bytes, len);
191+
return 0;
192+
}
174193

194+
/* Case 2: hex */
195+
err = _oid_from_hex(hex, &self->oid);
175196
if (err < 0)
176197
return -1;
177198

test/test_oid.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
# Import from the Standard Library
3535
from binascii import unhexlify
36+
from sys import version_info
3637
import unittest
3738

3839
# Import from pygit2
@@ -55,6 +56,16 @@ def test_hex(self):
5556
self.assertEqual(oid.raw, RAW)
5657
self.assertEqual(oid.hex, HEX)
5758

59+
def test_hex_bytes(self):
60+
if version_info.major == 2:
61+
hex = bytes(HEX)
62+
oid = Oid(hex=hex)
63+
self.assertEqual(oid.raw, RAW)
64+
self.assertEqual(oid.hex, HEX)
65+
else:
66+
hex = bytes(HEX, "ascii")
67+
self.assertRaises(TypeError, Oid, hex=hex)
68+
5869
def test_none(self):
5970
self.assertRaises(ValueError, Oid)
6071

test/test_repository.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@
4848

4949
HEAD_SHA = '784855caf26449a1914d2cf62d12b9374d76ae78'
5050
PARENT_SHA = 'f5e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87' # HEAD^
51-
A_HEX_SHA = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16'
52-
A_BIN_SHA = binascii.unhexlify(A_HEX_SHA.encode('ascii'))
51+
BLOB_HEX = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16'
52+
BLOB_RAW = binascii.unhexlify(BLOB_HEX.encode('ascii'))
53+
BLOB_OID = Oid(raw=BLOB_RAW)
5354

5455

5556
class RepositoryTest(utils.BareRepoTestCase):
@@ -71,15 +72,15 @@ def test_read(self):
7172
self.assertRaises(TypeError, self.repo.read, 123)
7273
self.assertRaisesWithArg(KeyError, '1' * 40, self.repo.read, '1' * 40)
7374

74-
ab = self.repo.read(A_BIN_SHA)
75-
a = self.repo.read(A_HEX_SHA)
75+
ab = self.repo.read(BLOB_OID)
76+
a = self.repo.read(BLOB_HEX)
7677
self.assertEqual(ab, a)
7778
self.assertEqual((GIT_OBJ_BLOB, b'a contents\n'), a)
7879

7980
a2 = self.repo.read('7f129fd57e31e935c6d60a0c794efe4e6927664b')
8081
self.assertEqual((GIT_OBJ_BLOB, b'a contents 2\n'), a2)
8182

82-
a_hex_prefix = A_HEX_SHA[:4]
83+
a_hex_prefix = BLOB_HEX[:4]
8384
a3 = self.repo.read(a_hex_prefix)
8485
self.assertEqual((GIT_OBJ_BLOB, b'a contents\n'), a3)
8586

@@ -93,29 +94,28 @@ def test_write(self):
9394

9495
def test_contains(self):
9596
self.assertRaises(TypeError, lambda: 123 in self.repo)
96-
self.assertTrue(A_BIN_SHA in self.repo)
97-
self.assertTrue(A_BIN_SHA[:10] in self.repo)
98-
self.assertTrue(A_HEX_SHA in self.repo)
99-
self.assertTrue(A_HEX_SHA[:10] in self.repo)
97+
self.assertTrue(BLOB_OID in self.repo)
98+
self.assertTrue(BLOB_HEX in self.repo)
99+
self.assertTrue(BLOB_HEX[:10] in self.repo)
100100
self.assertFalse('a' * 40 in self.repo)
101101
self.assertFalse('a' * 20 in self.repo)
102102

103103
def test_iterable(self):
104104
l = [ obj for obj in self.repo ]
105-
self.assertTrue(A_HEX_SHA in l)
105+
self.assertTrue(BLOB_HEX in l)
106106

107107
def test_lookup_blob(self):
108108
self.assertRaises(TypeError, lambda: self.repo[123])
109-
self.assertEqual(self.repo[A_BIN_SHA].hex, A_HEX_SHA)
110-
a = self.repo[A_HEX_SHA]
109+
self.assertEqual(self.repo[BLOB_OID].hex, BLOB_HEX)
110+
a = self.repo[BLOB_HEX]
111111
self.assertEqual(b'a contents\n', a.read_raw())
112-
self.assertEqual(A_HEX_SHA, a.hex)
112+
self.assertEqual(BLOB_HEX, a.hex)
113113
self.assertEqual(GIT_OBJ_BLOB, a.type)
114114

115115
def test_lookup_blob_prefix(self):
116-
a = self.repo[A_HEX_SHA[:5]]
116+
a = self.repo[BLOB_HEX[:5]]
117117
self.assertEqual(b'a contents\n', a.read_raw())
118-
self.assertEqual(A_HEX_SHA, a.hex)
118+
self.assertEqual(BLOB_HEX, a.hex)
119119
self.assertEqual(GIT_OBJ_BLOB, a.type)
120120

121121
def test_lookup_commit(self):

0 commit comments

Comments
 (0)