Skip to content
Closed
Changes from 1 commit
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
55bc286
add some rules to ruff
DinhHuy2010 Dec 21, 2024
2c06530
ignore unused imports
DinhHuy2010 Dec 21, 2024
484886a
Initial formatting and liniting fix of all files
DinhHuy2010 Dec 21, 2024
6330d4b
add type checking configuration (use pyright)
DinhHuy2010 Dec 21, 2024
325891b
add _libgit2.pyi
DinhHuy2010 Dec 21, 2024
aa37e2d
mega fix _pygit2.pyi
DinhHuy2010 Dec 21, 2024
b53b9a7
fix stubs
DinhHuy2010 Dec 21, 2024
c70241d
change lib to Any
DinhHuy2010 Dec 21, 2024
42b5129
fix pyright config
DinhHuy2010 Dec 21, 2024
5f6657e
fix _pygit2.pyi again
DinhHuy2010 Dec 21, 2024
4b3878b
fix enums.py
DinhHuy2010 Dec 21, 2024
49bc71b
add FilterSource
DinhHuy2010 Dec 21, 2024
7433683
yet another fix the _pygit2.pyi
DinhHuy2010 Dec 21, 2024
3aabbc7
add typing to credentials.py
DinhHuy2010 Dec 21, 2024
9a1affc
add typing to errors.py
DinhHuy2010 Dec 21, 2024
735ba5a
fix pyproject again
DinhHuy2010 Dec 21, 2024
5fc3b70
add filter_* functions to _pygit2.pyi
DinhHuy2010 Dec 21, 2024
95b003f
add typing to utils.py
DinhHuy2010 Dec 21, 2024
e71d03b
fix ffi.py
DinhHuy2010 Dec 21, 2024
9b68da8
initial commit of pygit2 __init__
DinhHuy2010 Dec 21, 2024
7afd694
remove pygit2 star imports
DinhHuy2010 Dec 22, 2024
b2680c3
fix pyproject again
DinhHuy2010 Dec 22, 2024
4970a94
fix pyproject
DinhHuy2010 Dec 22, 2024
40f44c1
fix pyproject again
DinhHuy2010 Dec 22, 2024
e3ed43f
initial commit of pygit2 callbacks.py
DinhHuy2010 Dec 22, 2024
35fb5e1
typing fix for __init__.py
DinhHuy2010 Dec 22, 2024
c3b01f8
fix typing for _build.py and _run.py
DinhHuy2010 Dec 24, 2024
0fe1aac
fix pyproject.toml
DinhHuy2010 Dec 25, 2024
58b88c2
add typing for packbuilder.py
DinhHuy2010 Dec 25, 2024
d8755fb
fix typing for utils
DinhHuy2010 Dec 25, 2024
8114f2b
hotfix for packbuilder.py
DinhHuy2010 Dec 25, 2024
071df9d
fix _pygit2.pyi
DinhHuy2010 Dec 25, 2024
9a10a41
initial stub for repository.py
DinhHuy2010 Dec 25, 2024
5f2d9ae
add typing for branches.py
DinhHuy2010 Dec 29, 2024
720881e
add typing to blob.py and fix _pygit2.pyi
DinhHuy2010 Dec 30, 2024
0e55fb3
add typing for blame.py and add _ctyping
DinhHuy2010 Dec 30, 2024
6ab13f7
Resolve confilcts from 'upstream/master'
DinhHuy2010 Dec 30, 2024
5dca60a
change pathtype name to StrOrBytesPath
DinhHuy2010 Dec 30, 2024
599f2b7
fix _ctyping
DinhHuy2010 Dec 30, 2024
d3be17a
fix _ctyping again
DinhHuy2010 Dec 30, 2024
dddd720
add maybe_bytes
DinhHuy2010 Dec 30, 2024
f019420
add typing to config.py
DinhHuy2010 Jan 13, 2025
86c62cd
Merge branch 'master' of https://github.com/libgit2/pygit2 into typec…
DinhHuy2010 Jan 13, 2025
b0da06b
fix typing
DinhHuy2010 Jan 13, 2025
0fab374
Solve confilcts
DinhHuy2010 Feb 17, 2025
8b46dec
Merge branch 'master' into typecheck
DinhHuy2010 Feb 17, 2025
48e0dce
fix config
DinhHuy2010 Feb 17, 2025
4dd70d6
fix stubs
DinhHuy2010 Dec 21, 2024
7f7a894
fix _libgit2.pyi
DinhHuy2010 Feb 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add typing to config.py
  • Loading branch information
DinhHuy2010 committed Jan 13, 2025
commit f0194204fed200245e5b4dd43f752be7e9b9074e
116 changes: 66 additions & 50 deletions pygit2/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,33 @@
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.

try:
from functools import cached_property
except ImportError:
from cached_property import cached_property
from __future__ import annotations

# Import from pygit2
import contextlib
from functools import cached_property
from typing import TYPE_CHECKING, Callable, cast

# Import from pygit2
from .errors import check_error
from .ffi import C, ffi
from .utils import to_bytes
from .utils import StrOrBytesPath, maybe_bytes, to_bytes

if TYPE_CHECKING:
from _cffi_backend import _CDataBase as CData

from ._ctyping import _CConfigEntry
from .repository import BaseRepository


def str_to_bytes(value, name):
def str_to_bytes(value: StrOrBytesPath, name: str):
if not isinstance(value, str):
raise TypeError(f'{name} must be a string')

return to_bytes(value)


class ConfigIterator:
def __init__(self, config, ptr):
def __init__(self, config: Config, ptr: CData):
self._iter = ptr
self._config = config

Expand All @@ -62,19 +67,23 @@ def _next_entry(self):
err = C.git_config_next(centry, self._iter)
check_error(err)

return ConfigEntry._from_c(centry[0], self)
return ConfigEntry._from_c(cast(_CConfigEntry, centry[0]), self)


class ConfigMultivarIterator(ConfigIterator):
def __next__(self):
def __next__(self): # type: ignore
entry = self._next_entry()
return entry.value


class Config:
"""Git configuration management."""

def __init__(self, path=None):
if TYPE_CHECKING:
_repo: BaseRepository
_config: CData

def __init__(self, path: StrOrBytesPath | None = None):
cconfig = ffi.new('git_config **')

if not path:
Expand All @@ -87,7 +96,7 @@ def __init__(self, path=None):
self._config = cconfig[0]

@classmethod
def from_c(cls, repo, ptr):
def from_c(cls, repo: BaseRepository, ptr: CData):
config = cls.__new__(cls)
config._repo = repo
config._config = ptr
Expand All @@ -98,15 +107,15 @@ def __del__(self):
with contextlib.suppress(AttributeError):
C.git_config_free(self._config)

def _get(self, key):
key = str_to_bytes(key, 'key')
def _get(self, key: str | bytes):
rkey = str_to_bytes(key, 'key')

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

return err, ConfigEntry._from_c(entry[0])
return err, ConfigEntry._from_c(cast(_CConfigEntry, entry[0]))

def _get_entry(self, key):
def _get_entry(self, key: str | bytes):
err, entry = self._get(key)

if err == C.GIT_ENOTFOUND:
Expand All @@ -115,8 +124,8 @@ def _get_entry(self, key):
check_error(err)
return entry

def __contains__(self, key):
err, cstr = self._get(key)
def __contains__(self, key: str):
err, _ = self._get(key)

if err == C.GIT_ENOTFOUND:
return False
Expand All @@ -125,7 +134,7 @@ def __contains__(self, key):

return True

def __getitem__(self, key):
def __getitem__(self, key: str):
"""
When using the mapping interface, the value is returned as a string. In
order to apply the git-config parsing rules, you can use
Expand All @@ -135,23 +144,23 @@ def __getitem__(self, key):

return entry.value

def __setitem__(self, key, value):
key = str_to_bytes(key, 'key')
def __setitem__(self, key: str, value: int | bool | str):
rkey = str_to_bytes(key, 'key')

err = 0
if isinstance(value, bool):
err = C.git_config_set_bool(self._config, key, value)
err = C.git_config_set_bool(self._config, rkey, value)
elif isinstance(value, int):
err = C.git_config_set_int64(self._config, key, value)
err = C.git_config_set_int64(self._config, rkey, value)
else:
err = C.git_config_set_string(self._config, key, to_bytes(value))
err = C.git_config_set_string(self._config, rkey, to_bytes(value))

check_error(err)

def __delitem__(self, key):
key = str_to_bytes(key, 'key')
def __delitem__(self, key: str):
rkey = str_to_bytes(key, 'key')

err = C.git_config_delete_entry(self._config, key)
err = C.git_config_delete_entry(self._config, rkey)
check_error(err)

def __iter__(self):
Expand All @@ -165,24 +174,27 @@ def __iter__(self):
err = C.git_config_iterator_new(citer, self._config)
check_error(err)

return ConfigIterator(self, citer[0])
ptr = cast(CData, citer[0])

def get_multivar(self, name, regex=None):
return ConfigIterator(self, ptr)

def get_multivar(self, name: str | bytes, regex: CData | str | bytes | None = None):
"""Get each value of a multivar ''name'' as a list of strings.

The optional ''regex'' parameter is expected to be a regular expression
to filter the variables we're interested in.
"""
name = str_to_bytes(name, 'name')
regex = to_bytes(regex or None)
regex = to_bytes(regex)

citer = ffi.new('git_config_iterator **')
err = C.git_config_multivar_iterator_new(citer, self._config, name, regex)
check_error(err)
cit = cast(CData, citer[0])

return ConfigMultivarIterator(self, citer[0])
return ConfigMultivarIterator(self, cit)

def set_multivar(self, name, regex, value):
def set_multivar(self, name: str | bytes, regex: str | bytes, value: str | bytes):
"""Set a multivar ''name'' to ''value''. ''regexp'' is a regular
expression to indicate which values to replace.
"""
Expand All @@ -193,7 +205,7 @@ def set_multivar(self, name, regex, value):
err = C.git_config_set_multivar(self._config, name, regex, value)
check_error(err)

def delete_multivar(self, name, regex):
def delete_multivar(self, name: str | bytes, regex: str | bytes):
"""Delete a multivar ''name''. ''regexp'' is a regular expression to
indicate which values to delete.
"""
Expand All @@ -203,7 +215,7 @@ def delete_multivar(self, name, regex):
err = C.git_config_delete_multivar(self._config, name, regex)
check_error(err)

def get_bool(self, key):
def get_bool(self, key: str | bytes):
"""Look up *key* and parse its value as a boolean as per the git-config
rules. Return a boolean value (True or False).

Expand All @@ -216,9 +228,9 @@ def get_bool(self, key):
err = C.git_config_parse_bool(res, entry.c_value)
check_error(err)

return res[0] != 0
return cast(int, res[0]) != 0

def get_int(self, key):
def get_int(self, key: str | bytes):
"""Look up *key* and parse its value as an integer as per the git-config
rules. Return an integer.

Expand All @@ -231,9 +243,9 @@ def get_int(self, key):
err = C.git_config_parse_int64(res, entry.c_value)
check_error(err)

return res[0]
return cast(int, res[0])

def add_file(self, path, level=0, force=0):
def add_file(self, path: StrOrBytesPath, level: int = 0, force: int = 0):
"""Add a config file instance to an existing config."""

err = C.git_config_add_file_ondisk(
Expand All @@ -251,41 +263,42 @@ def snapshot(self):
err = C.git_config_snapshot(ccfg, self._config)
check_error(err)

return Config.from_c(self._repo, ccfg[0])
return Config.from_c(self._repo, cast(CData, ccfg[0]))

#
# Methods to parse a string according to the git-config rules
#

@staticmethod
def parse_bool(text):
def parse_bool(text: str):
res = ffi.new('int *')
err = C.git_config_parse_bool(res, to_bytes(text))
check_error(err)

return res[0] != 0
return cast(int, res[0]) != 0

@staticmethod
def parse_int(text):
def parse_int(text: str):
res = ffi.new('int64_t *')
err = C.git_config_parse_int64(res, to_bytes(text))
check_error(err)

return res[0]
return cast(int, res[0])

#
# Static methods to get specialized version of the config
#

@staticmethod
def _from_found_config(fn):
def _from_found_config(fn: Callable[[CData], int]):
buf = ffi.new('git_buf *', (ffi.NULL, 0))
err = fn(buf)
check_error(err, io=True)
cpath = ffi.string(buf.ptr).decode('utf-8')
cpath = maybe_bytes(cast(CData, buf.ptr))
assert cpath
C.git_buf_dispose(buf)

return Config(cpath)
return Config(cpath.decode('utf-8'))

@staticmethod
def get_system_config():
Expand All @@ -306,8 +319,11 @@ def get_xdg_config():
class ConfigEntry:
"""An entry in a configuation object."""

if TYPE_CHECKING:
_entry: _CConfigEntry

@classmethod
def _from_c(cls, ptr, iterator=None):
def _from_c(cls, ptr: _CConfigEntry, iterator: ConfigIterator | None = None):
"""Builds the entry from a ``git_config_entry`` pointer.

``iterator`` must be a ``ConfigIterator`` instance if the entry was
Expand Down Expand Up @@ -341,11 +357,11 @@ def c_value(self):

@cached_property
def raw_name(self):
return ffi.string(self._entry.name)
return cast(bytes, maybe_bytes(self._entry.name))

@cached_property
def raw_value(self):
return ffi.string(self.c_value)
return cast(bytes, maybe_bytes(self.c_value))

@cached_property
def level(self):
Expand Down