Skip to content

Commit 25c98a8

Browse files
committed
improve types according to test/test_config.py
1 parent 8ec1937 commit 25c98a8

File tree

5 files changed

+58
-18
lines changed

5 files changed

+58
-18
lines changed

pygit2/_libgit2/ffi.pyi

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,14 @@ class GitCommitC:
120120
pass
121121

122122
class GitConfigC:
123+
# incomplete
123124
pass
124125

126+
class GitConfigEntryC:
127+
# incomplete
128+
name: char_pointer
129+
level: int
130+
125131
class GitDescribeFormatOptionsC:
126132
version: int
127133
abbreviated_size: int
@@ -229,6 +235,10 @@ def new(a: Literal['git_commit **']) -> _Pointer[GitCommitC]: ...
229235
@overload
230236
def new(a: Literal['git_config *']) -> GitConfigC: ...
231237
@overload
238+
def new(a: Literal['git_config **']) -> _Pointer[GitConfigC]: ...
239+
@overload
240+
def new(a: Literal['git_config_entry **']) -> _Pointer[GitConfigEntryC]: ...
241+
@overload
232242
def new(a: Literal['git_describe_format_options *']) -> GitDescribeFormatOptionsC: ...
233243
@overload
234244
def new(a: Literal['git_describe_options *']) -> GitDescribeOptionsC: ...

pygit2/_pygit2.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ from ._libgit2.ffi import (
2727
)
2828
from .blame import Blame
2929
from .callbacks import CheckoutCallbacks
30+
from .config import Config
3031
from .enums import (
3132
ApplyLocation,
3233
AttrCheck,
@@ -781,6 +782,8 @@ class Repository:
781782
) -> None: ...
782783
def cherrypick(self, id: _OidArg) -> None: ...
783784
def compress_references(self) -> None: ...
785+
@property
786+
def config(self) -> Config: ...
784787
def create_blob(self, data: bytes) -> Oid: ...
785788
def create_blob_fromdisk(self, path: str) -> Oid: ...
786789
def create_blob_fromiobase(self, iobase: IOBase) -> Oid: ...

pygit2/config.py

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
2424
# Boston, MA 02110-1301, USA.
2525

26+
from os import PathLike
27+
from typing import TYPE_CHECKING
28+
2629
try:
2730
from functools import cached_property
2831
except ImportError:
@@ -33,8 +36,11 @@
3336
from .ffi import C, ffi
3437
from .utils import to_bytes
3538

39+
if TYPE_CHECKING:
40+
from ._libgit2.ffi import GitConfigC, GitConfigEntryC, GitRepositoryC
41+
3642

37-
def str_to_bytes(value, name):
43+
def str_to_bytes(value: str | PathLike[str] | bytes, name: str) -> bytes:
3844
if not isinstance(value, str):
3945
raise TypeError(f'{name} must be a string')
4046

@@ -72,41 +78,44 @@ def __next__(self):
7278
class Config:
7379
"""Git configuration management."""
7480

75-
def __init__(self, path=None):
81+
_repo: 'GitRepositoryC'
82+
_config: 'GitConfigC'
83+
84+
def __init__(self, path: str | None = None) -> None:
7685
cconfig = ffi.new('git_config **')
7786

7887
if not path:
7988
err = C.git_config_new(cconfig)
8089
else:
81-
path = str_to_bytes(path, 'path')
82-
err = C.git_config_open_ondisk(cconfig, path)
90+
path_bytes = str_to_bytes(path, 'path')
91+
err = C.git_config_open_ondisk(cconfig, path_bytes)
8392

8493
check_error(err, io=True)
8594
self._config = cconfig[0]
8695

8796
@classmethod
88-
def from_c(cls, repo, ptr):
97+
def from_c(cls, repo: 'GitRepositoryC', ptr: 'GitConfigC') -> 'Config':
8998
config = cls.__new__(cls)
9099
config._repo = repo
91100
config._config = ptr
92101

93102
return config
94103

95-
def __del__(self):
104+
def __del__(self) -> None:
96105
try:
97106
C.git_config_free(self._config)
98107
except AttributeError:
99108
pass
100109

101-
def _get(self, key):
110+
def _get(self, key: str | bytes) -> tuple[object, 'ConfigEntry']:
102111
key = str_to_bytes(key, 'key')
103112

104113
entry = ffi.new('git_config_entry **')
105114
err = C.git_config_get_entry(entry, self._config, key)
106115

107116
return err, ConfigEntry._from_c(entry[0])
108117

109-
def _get_entry(self, key):
118+
def _get_entry(self, key: str | bytes) -> 'ConfigEntry':
110119
err, entry = self._get(key)
111120

112121
if err == C.GIT_ENOTFOUND:
@@ -306,8 +315,13 @@ def get_xdg_config():
306315
class ConfigEntry:
307316
"""An entry in a configuration object."""
308317

318+
_entry: 'GitConfigEntryC'
319+
iterator: ConfigIterator | None
320+
309321
@classmethod
310-
def _from_c(cls, ptr, iterator=None):
322+
def _from_c(
323+
cls, ptr: 'GitConfigEntryC', iterator: ConfigIterator | None = None
324+
) -> 'ConfigEntry':
311325
"""Builds the entry from a ``git_config_entry`` pointer.
312326
313327
``iterator`` must be a ``ConfigIterator`` instance if the entry was
@@ -330,7 +344,7 @@ def _from_c(cls, ptr, iterator=None):
330344

331345
return entry
332346

333-
def __del__(self):
347+
def __del__(self) -> None:
334348
if self.iterator is None:
335349
C.git_config_entry_free(self._entry)
336350

@@ -340,24 +354,24 @@ def c_value(self):
340354
return self._entry.value
341355

342356
@cached_property
343-
def raw_name(self):
357+
def raw_name(self) -> bytes:
344358
return ffi.string(self._entry.name)
345359

346360
@cached_property
347-
def raw_value(self):
361+
def raw_value(self) -> bytes:
348362
return ffi.string(self.c_value)
349363

350364
@cached_property
351-
def level(self):
365+
def level(self) -> int:
352366
"""The entry's ``git_config_level_t`` value."""
353367
return self._entry.level
354368

355369
@property
356-
def name(self):
370+
def name(self) -> str:
357371
"""The entry's name."""
358372
return self.raw_name.decode('utf-8')
359373

360374
@property
361-
def value(self):
375+
def value(self) -> str:
362376
"""The entry's value as a string."""
363377
return self.raw_value.decode('utf-8')

pygit2/utils.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
import contextlib
2727
import os
28-
from typing import Generic, Iterator, Protocol, TypeVar, Union
28+
from typing import Generic, Iterator, Protocol, TypeVar, Union, overload
2929

3030
# Import from pygit2
3131
from .ffi import C, ffi
@@ -38,6 +38,18 @@ def maybe_string(ptr):
3838
return ffi.string(ptr).decode('utf8', errors='surrogateescape')
3939

4040

41+
@overload
42+
def to_bytes(
43+
s: Union[str, bytes, os.PathLike[str]],
44+
encoding: str = 'utf-8',
45+
errors: str = 'strict',
46+
) -> bytes: ...
47+
@overload
48+
def to_bytes(
49+
s: Union['ffi.NULL_TYPE', None],
50+
encoding: str = 'utf-8',
51+
errors: str = 'strict',
52+
) -> Union['ffi.NULL_TYPE']: ...
4153
def to_bytes(
4254
s: Union[str, bytes, 'ffi.NULL_TYPE', os.PathLike[str], None],
4355
encoding: str = 'utf-8',

test/test_config.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,19 @@
2424
# Boston, MA 02110-1301, USA.
2525

2626
from pathlib import Path
27+
from typing import Generator
2728

2829
import pytest
2930

30-
from pygit2 import Config
31+
from pygit2 import Config, Repository
3132

3233
from . import utils
3334

3435
CONFIG_FILENAME = 'test_config'
3536

3637

3738
@pytest.fixture
38-
def config(testrepo):
39+
def config(testrepo: Repository) -> Generator[object, None, None]:
3940
yield testrepo.config
4041
try:
4142
Path(CONFIG_FILENAME).unlink()

0 commit comments

Comments
 (0)