Skip to content

Commit 58d1271

Browse files
committed
create type interface for _libgit2.ffi
1 parent 0d7e6f9 commit 58d1271

File tree

9 files changed

+330
-64
lines changed

9 files changed

+330
-64
lines changed

pygit2/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def clone_repository(
164164
callbacks: RemoteCallbacks | None = None,
165165
depth: int = 0,
166166
proxy: None | bool | str = None,
167-
):
167+
) -> Repository:
168168
"""
169169
Clones a new Git repository from *url* in the given *path*.
170170

pygit2/_libgit2/ffi.pyi

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
# Copyright 2010-2025 The pygit2 contributors
2+
#
3+
# This file is free software; you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License, version 2,
5+
# as published by the Free Software Foundation.
6+
#
7+
# In addition to the permissions in the GNU General Public License,
8+
# the authors give you unlimited permission to link the compiled
9+
# version of this file into combinations with other programs,
10+
# and to distribute those combinations without any restriction
11+
# coming from the use of this file. (The General Public License
12+
# restrictions do apply in other respects; for example, they cover
13+
# modification of the file, and distribution when not linked into
14+
# a combined executable.)
15+
#
16+
# This file is distributed in the hope that it will be useful, but
17+
# WITHOUT ANY WARRANTY; without even the implied warranty of
18+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19+
# General Public License for more details.
20+
#
21+
# You should have received a copy of the GNU General Public License
22+
# along with this program; see the file COPYING. If not, write to
23+
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
24+
# Boston, MA 02110-1301, USA.
25+
26+
from typing import Literal, overload, NewType, TypeVar, Generic, Any, SupportsIndex
27+
from typing import NewType, Literal, TypeVar, Generic, overload
28+
from pygit2._pygit2 import Repository
29+
30+
T = TypeVar('T')
31+
32+
NULL_TYPE = NewType('NULL_TYPE', object)
33+
NULL: NULL_TYPE = ...
34+
35+
char = NewType('char', object)
36+
char_pointer = NewType('char_pointer', object)
37+
38+
class _Pointer(Generic[T]):
39+
def __setitem__(self, item: Literal[0], a: T) -> None: ...
40+
@overload
41+
def __getitem__(self, item: Literal[0]) -> T: ...
42+
@overload
43+
def __getitem__(self, item: slice[None, None, None]) -> bytes: ...
44+
45+
class GitTimeC:
46+
# incomplete
47+
time: int
48+
offset: int
49+
50+
class GitSignatureC:
51+
name: char_pointer
52+
email: char_pointer
53+
when: GitTimeC
54+
55+
class GitHunkC:
56+
# incomplete
57+
boundary: char
58+
final_start_line_number: int
59+
final_signature: GitSignatureC
60+
orig_signature: GitSignatureC
61+
orig_start_line_number: int
62+
orig_path: char_pointer
63+
lines_in_hunk: int
64+
65+
class GitRepositoryC:
66+
# incomplete
67+
# TODO: this has to be unified with pygit2._pygit2(pyi).Repository
68+
def _from_c(cls, ptr: 'GitRepositoryC', owned: bool) -> 'Repository': ...
69+
70+
class GitFetchOptionsC:
71+
# TODO: FetchOptions exist in _pygit2.pyi
72+
# incomplete
73+
depth: int
74+
75+
class GitSubmoduleC:
76+
pass
77+
78+
class GitSubmoduleUpdateOptionsC:
79+
fetch_opts: GitFetchOptionsC
80+
81+
class UnsignedIntC:
82+
def __getitem__(self, item: Literal[0]) -> int: ...
83+
84+
class GitOidC:
85+
id: _Pointer[bytes]
86+
87+
class GitBlameOptionsC:
88+
flags: int
89+
min_match_characters: int
90+
newest_commit: object
91+
oldest_commit: object
92+
min_line: int
93+
max_line: int
94+
95+
class GitBlameC:
96+
# incomplete
97+
pass
98+
99+
class GitMergeOptionsC:
100+
file_favor: int
101+
flags: int
102+
file_flags: int
103+
104+
class GitAnnotatedCommitC:
105+
pass
106+
107+
class GitAttrOptionsC:
108+
# incomplete
109+
version: int
110+
flags: int
111+
112+
class GitBufC:
113+
ptr: char_pointer
114+
115+
class GitCheckoutOptionsC:
116+
# incomplete
117+
checkout_strategy: int
118+
119+
class GitCommitC:
120+
pass
121+
122+
class GitConfigC:
123+
pass
124+
125+
class GitDescribeFormatOptionsC:
126+
version: int
127+
abbreviated_size: int
128+
always_use_long_format: int
129+
dirty_suffix: char_pointer
130+
131+
class GitDescribeOptionsC:
132+
version: int
133+
max_candidates_tags: int
134+
describe_strategy: int
135+
pattern: char_pointer
136+
only_follow_first_parent: int
137+
show_commit_oid_as_fallback: int
138+
139+
class GitDescribeResultC:
140+
pass
141+
142+
class GitIndexC:
143+
pass
144+
145+
class GitMergeFileResultC:
146+
pass
147+
148+
class GitObjectC:
149+
pass
150+
151+
class GitStashSaveOptionsC:
152+
version: int
153+
flags: int
154+
stasher: GitSignatureC
155+
message: char_pointer
156+
paths: GitStrrayC
157+
158+
class GitStrrayC:
159+
pass
160+
161+
class GitTreeC:
162+
pass
163+
164+
class GitRepositoryInitOptionsC:
165+
version: int
166+
flags: int
167+
mode: int
168+
workdir_path: char_pointer
169+
description: char_pointer
170+
template_path: char_pointer
171+
initial_head: char_pointer
172+
origin_url: char_pointer
173+
174+
class GitCloneOptionsC:
175+
pass
176+
177+
class GitProxyTC:
178+
pass
179+
180+
class GitProxyOptionsC:
181+
version: int
182+
type: GitProxyTC
183+
url: char_pointer
184+
# credentials
185+
# certificate_check
186+
# payload
187+
188+
class GitRemoteC:
189+
pass
190+
191+
class GitReferenceC:
192+
pass
193+
194+
def string(a: char_pointer) -> bytes: ...
195+
@overload
196+
def new(a: Literal['git_repository **']) -> _Pointer[GitRepositoryC]: ...
197+
@overload
198+
def new(a: Literal['git_remote **']) -> _Pointer[GitRemoteC]: ...
199+
@overload
200+
def new(a: Literal['git_repository_init_options *']) -> GitRepositoryInitOptionsC: ...
201+
@overload
202+
def new(a: Literal['git_submodule_update_options *']) -> GitSubmoduleUpdateOptionsC: ...
203+
@overload
204+
def new(a: Literal['git_submodule **']) -> _Pointer[GitSubmoduleC]: ...
205+
@overload
206+
def new(a: Literal['unsigned int *']) -> UnsignedIntC: ...
207+
@overload
208+
def new(a: Literal['git_proxy_options *']) -> GitProxyOptionsC: ...
209+
@overload
210+
def new(a: Literal['git_oid *']) -> GitOidC: ...
211+
@overload
212+
def new(a: Literal['git_blame **']) -> _Pointer[GitBlameC]: ...
213+
@overload
214+
def new(a: Literal['git_clone_options *']) -> GitCloneOptionsC: ...
215+
@overload
216+
def new(a: Literal['git_merge_options *']) -> GitMergeOptionsC: ...
217+
@overload
218+
def new(a: Literal['git_blame_options *']) -> GitBlameOptionsC: ...
219+
@overload
220+
def new(a: Literal['git_annotated_commit **']) -> _Pointer[GitAnnotatedCommitC]: ...
221+
@overload
222+
def new(a: Literal['git_attr_options *']) -> GitAttrOptionsC: ...
223+
@overload
224+
def new(a: Literal['git_buf *']) -> GitBufC: ...
225+
@overload
226+
def new(a: Literal['git_checkout_options *']) -> GitCheckoutOptionsC: ...
227+
@overload
228+
def new(a: Literal['git_commit **']) -> _Pointer[GitCommitC]: ...
229+
@overload
230+
def new(a: Literal['git_config *']) -> GitConfigC: ...
231+
@overload
232+
def new(a: Literal['git_describe_format_options *']) -> GitDescribeFormatOptionsC: ...
233+
@overload
234+
def new(a: Literal['git_describe_options *']) -> GitDescribeOptionsC: ...
235+
@overload
236+
def new(a: Literal['git_describe_result *']) -> GitDescribeResultC: ...
237+
@overload
238+
def new(a: Literal['git_describe_result **']) -> _Pointer[GitDescribeResultC]: ...
239+
@overload
240+
def new(a: Literal['struct git_reference **']) -> _Pointer[GitReferenceC]: ...
241+
@overload
242+
def new(a: Literal['git_index **']) -> _Pointer[GitIndexC]: ...
243+
@overload
244+
def new(a: Literal['git_merge_file_result *']) -> GitMergeFileResultC: ...
245+
@overload
246+
def new(a: Literal['git_object *']) -> GitObjectC: ...
247+
@overload
248+
def new(a: Literal['git_object **']) -> _Pointer[GitObjectC]: ...
249+
@overload
250+
def new(a: Literal['git_signature *']) -> GitSignatureC: ...
251+
@overload
252+
def new(a: Literal['git_signature **']) -> _Pointer[GitSignatureC]: ...
253+
@overload
254+
def new(a: Literal['git_stash_save_options *']) -> GitStashSaveOptionsC: ...
255+
@overload
256+
def new(a: Literal['git_tree **']) -> _Pointer[GitTreeC]: ...
257+
@overload
258+
def new(a: Literal['git_buf *'], b: tuple[NULL_TYPE, Literal[0]]) -> GitBufC: ...
259+
@overload
260+
def new(a: Literal['char **']) -> _Pointer[char_pointer]: ...
261+
@overload
262+
def new(a: Literal['char[]', 'char []'], b: bytes | NULL_TYPE) -> char_pointer: ...
263+
def addressof(a: object, attribute: str) -> _Pointer[object]: ...
264+
265+
class buffer(bytes):
266+
def __init__(self, a: object) -> None: ...
267+
def __setitem__(self, item: slice[None, None, None], value: bytes) -> None: ...
268+
@overload
269+
def __getitem__(self, item: SupportsIndex) -> int: ...
270+
@overload
271+
def __getitem__(self, item: slice[Any, Any, Any]) -> bytes: ...
272+
273+
def cast(a: Literal['int'], b: object) -> int: ...

pygit2/_pygit2.pyi

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
from typing import Iterator, Literal, Optional, overload, Type, TypedDict
1+
from typing import (
2+
Iterator,
3+
Literal,
4+
Optional,
5+
overload,
6+
Type,
7+
TypedDict,
8+
TypeVar,
9+
Generic,
10+
)
211
from io import IOBase, DEFAULT_BUFFER_SIZE
312
from pathlib import Path
413
from queue import Queue
@@ -29,7 +38,14 @@ from .enums import (
2938
)
3039
from collections.abc import Generator
3140

32-
from ._pygit2_c import GitSignatureC, _Pointer
41+
from ._libgit2.ffi import (
42+
_Pointer,
43+
GitObjectC,
44+
GitCommitC,
45+
GitRepositoryC,
46+
GitProxyOptionsC,
47+
GitSignatureC,
48+
)
3349

3450
from .repository import BaseRepository
3551
from .submodules import SubmoduleCollection, Submodule
@@ -287,8 +303,10 @@ GIT_FILTER_NO_SYSTEM_ATTRIBUTES: int
287303
GIT_FILTER_ATTRIBUTES_FROM_HEAD: int
288304
GIT_FILTER_ATTRIBUTES_FROM_COMMIT: int
289305

290-
class Object:
291-
_pointer: bytes
306+
T = TypeVar('T')
307+
308+
class _ObjectBase(Generic[T]):
309+
_pointer: _Pointer[T]
292310
filemode: FileMode
293311
id: Oid
294312
name: str | None
@@ -320,6 +338,9 @@ class Object:
320338
def __lt__(self, other) -> bool: ...
321339
def __ne__(self, other) -> bool: ...
322340

341+
class Object(_ObjectBase[GitObjectC]):
342+
pass
343+
323344
class Reference:
324345
name: str
325346
raw_name: bytes
@@ -395,7 +416,7 @@ class Branch(Reference):
395416
class FetchOptions:
396417
# incomplete
397418
depth: int
398-
proxy_opts: ProxyOpts
419+
proxy_opts: GitProxyOptionsC
399420

400421
class CloneOptions:
401422
# incomplete
@@ -410,7 +431,8 @@ class CloneOptions:
410431
remote_cb: object
411432
remote_cb_payload: object
412433

413-
class Commit(Object):
434+
class Commit(_ObjectBase[GitCommitC]):
435+
_pointer: _Pointer[GitCommitC]
414436
author: Signature
415437
commit_time: int
416438
commit_time_offset: int
@@ -640,16 +662,11 @@ class _StrArray:
640662
# incomplete
641663
count: int
642664

643-
class ProxyOpts:
644-
# incomplete
645-
type: object
646-
url: str
647-
648665
class PushOptions:
649666
version: int
650667
pb_parallelism: int
651668
callbacks: object # TODO
652-
proxy_opts: ProxyOpts
669+
proxy_opts: GitProxyOptionsC
653670
follow_redirects: object # TODO
654671
custom_headers: _StrArray
655672
remote_push_options: _StrArray
@@ -696,7 +713,7 @@ class Branches:
696713
def __contains__(self, name: _OidArg) -> bool: ...
697714

698715
class Repository:
699-
_pointer: bytes
716+
_pointer: GitRepositoryC
700717
default_signature: Signature
701718
head: Reference
702719
head_is_detached: bool
@@ -716,7 +733,8 @@ class Repository:
716733
def __init__(self, *args, **kwargs) -> None: ...
717734
def TreeBuilder(self, src: Tree | _OidArg = ...) -> TreeBuilder: ...
718735
def _disown(self, *args, **kwargs) -> None: ...
719-
def _from_c(self, *args, **kwargs) -> 'Repository': ...
736+
@classmethod
737+
def _from_c(cls, ptr: 'GitRepositoryC', owned: bool) -> 'Repository': ...
720738
def __getitem__(self, key: str | Oid) -> Object: ...
721739
def add_worktree(self, name: str, path: str, ref: Reference = ...) -> Worktree: ...
722740
def applies(

0 commit comments

Comments
 (0)