Skip to content

Commit 555b1f3

Browse files
committed
Add Odb.read_header
1 parent b4ed388 commit 555b1f3

File tree

3 files changed

+55
-2
lines changed

3 files changed

+55
-2
lines changed

pygit2/_pygit2.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ class Odb:
519519
def add_disk_alternate(self, path: str | Path) -> None: ...
520520
def exists(self, oid: _OidArg) -> bool: ...
521521
def read(self, oid: _OidArg) -> tuple[ObjectType, bytes]: ...
522+
def read_header(self, oid: _OidArg) -> tuple[ObjectType, int]: ...
522523
def write(self, type: int, data: bytes | str) -> Oid: ...
523524
def __contains__(self, other: _OidArg) -> bool: ...
524525
def __iter__(self) -> Iterator[Oid]: ... # Odb_as_iter

src/odb.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,44 @@ Odb_read(Odb *self, PyObject *py_hex)
208208
return tuple;
209209
}
210210

211+
PyDoc_STRVAR(Odb_read_header__doc__,
212+
"read_header(oid: Oid) -> tuple[enums.ObjectType, size\n"
213+
"\n"
214+
"Read the header of an object from the database, without reading its full\n"
215+
"contents.\n"
216+
"\n"
217+
"The header includes the type and the length of an object.\n"
218+
"\n"
219+
"Note that most backends do not support reading only the header of an object,\n"
220+
"so the whole object may be read and then the header will be returned.");
221+
222+
PyObject *
223+
Odb_read_header(Odb *self, PyObject *py_hex)
224+
{
225+
git_oid oid;
226+
int err;
227+
size_t len;
228+
git_object_t type;
229+
PyObject* type_enum;
230+
PyObject* tuple;
231+
232+
len = py_oid_to_git_oid(py_hex, &oid);
233+
if (len == 0)
234+
return NULL;
235+
236+
err = git_odb_read_header(&len, &type, self->odb, &oid);
237+
if (err != 0) {
238+
Error_set_oid(err, &oid, len);
239+
return NULL;
240+
}
241+
242+
// Convert type to ObjectType enum
243+
type_enum = pygit2_enum(ObjectTypeEnum, type);
244+
245+
tuple = Py_BuildValue("(On)", type_enum, len);
246+
return tuple;
247+
}
248+
211249
PyDoc_STRVAR(Odb_write__doc__,
212250
"write(type: int, data: bytes) -> Oid\n"
213251
"\n"
@@ -309,6 +347,7 @@ Odb_add_backend(Odb *self, PyObject *args)
309347
PyMethodDef Odb_methods[] = {
310348
METHOD(Odb, add_disk_alternate, METH_O),
311349
METHOD(Odb, read, METH_O),
350+
METHOD(Odb, read_header, METH_O),
312351
METHOD(Odb, write, METH_VARARGS),
313352
METHOD(Odb, exists, METH_O),
314353
METHOD(Odb, add_backend, METH_VARARGS),

test/test_odb.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
BLOB_HEX = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16'
4242
BLOB_RAW = binascii.unhexlify(BLOB_HEX.encode('ascii'))
4343
BLOB_OID = Oid(raw=BLOB_RAW)
44+
BLOB_CONTENTS = b'a contents\n'
4445

4546

4647
def test_emptyodb(barerepo: Repository) -> None:
@@ -75,7 +76,7 @@ def test_read(odb: Odb) -> None:
7576
ab = odb.read(BLOB_OID)
7677
a = odb.read(BLOB_HEX)
7778
assert ab == a
78-
assert (ObjectType.BLOB, b'a contents\n') == a
79+
assert (ObjectType.BLOB, BLOB_CONTENTS) == a
7980
assert isinstance(a[0], ObjectType)
8081

8182
a2 = odb.read('7f129fd57e31e935c6d60a0c794efe4e6927664b')
@@ -84,10 +85,22 @@ def test_read(odb: Odb) -> None:
8485

8586
a_hex_prefix = BLOB_HEX[:4]
8687
a3 = odb.read(a_hex_prefix)
87-
assert (ObjectType.BLOB, b'a contents\n') == a3
88+
assert (ObjectType.BLOB, BLOB_CONTENTS) == a3
8889
assert isinstance(a3[0], ObjectType)
8990

9091

92+
def test_read_header(odb: Odb) -> None:
93+
with pytest.raises(TypeError):
94+
odb.read_header(123) # type: ignore
95+
utils.assertRaisesWithArg(KeyError, '1' * 40, odb.read_header, '1' * 40)
96+
97+
ab = odb.read_header(BLOB_OID)
98+
a = odb.read_header(BLOB_HEX)
99+
assert ab == a
100+
assert (ObjectType.BLOB, len(BLOB_CONTENTS)) == a
101+
assert isinstance(a[0], ObjectType)
102+
103+
91104
def test_write(odb: Odb) -> None:
92105
data = b'hello world'
93106
# invalid object type

0 commit comments

Comments
 (0)