Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[mypy]

[mypy-test.*]
disallow_untyped_defs = True
24 changes: 14 additions & 10 deletions pygit2/_pygit2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ class Repository:
def _from_c(cls, ptr: 'GitRepositoryC', owned: bool) -> 'Repository': ...
def __iter__(self) -> Iterator[Oid]: ...
def __getitem__(self, key: str | Oid) -> Object: ...
def __contains__(self, name: _OidArg) -> bool: ...
def add_worktree(
self, name: str, path: str | Path, ref: Reference = ...
) -> Worktree: ...
Expand Down Expand Up @@ -866,8 +867,8 @@ class Repository:
) -> Oid: ...
def diff(
self,
a: None | str | bytes | Oid | Reference = None,
b: None | str | bytes | Oid | Reference = None,
a: None | str | bytes | Commit | Oid | Reference = None,
b: None | str | bytes | Commit | Oid | Reference = None,
cached: bool = False,
flags: DiffOption = DiffOption.NORMAL,
context_lines: int = 3,
Expand Down Expand Up @@ -976,6 +977,7 @@ class Repository:
def raw_listall_references(self) -> list[bytes]: ...
@property
def raw_message(self) -> bytes: ...
def read(self, oid: _OidArg) -> tuple[int, bytes]: ...
def remove_message(self) -> None: ...
def references_iterator_init(self) -> Iterator[Reference]: ...
def references_iterator_next(
Expand All @@ -992,6 +994,7 @@ class Repository:
def revert_commit(
self, revert_commit: Commit, our_commit: Commit, mainline: int = 0
) -> Index: ...
def set_head(self, target: _OidArg) -> None: ...
def set_ident(self, name: str, email: str) -> None: ...
def set_odb(self, odb: Odb) -> None: ...
def set_refdb(self, refdb: Refdb) -> None: ...
Expand All @@ -1007,7 +1010,7 @@ class Repository:
include_ignored: bool = False,
keep_all: bool = False,
paths: list[str] | None = None,
) -> None: ...
) -> Oid: ...
def stash_apply(
self,
index: int = 0,
Expand All @@ -1033,6 +1036,7 @@ class Repository:
def walk(
self, oid: _OidArg | None, sort_mode: SortMode = SortMode.NONE
) -> Walker: ...
def write(self, type: int, data: bytes | str) -> Oid: ...
def write_archive(
self,
treeish: str | Tree | Object | Oid,
Expand All @@ -1057,7 +1061,7 @@ class Signature:
time: int
def __init__(
self,
name: str,
name: str | bytes,
email: str,
time: int = -1,
offset: int = 0,
Expand Down Expand Up @@ -1113,11 +1117,11 @@ class Tree(Object):
interhunk_lines: int = 0,
) -> Diff: ...
def __contains__(self, other: str) -> bool: ... # Tree_contains
def __getitem__(self, index: str | int) -> Object: ... # Tree_subscript
def __getitem__(self, index: str | int) -> Tree | Blob: ... # Tree_subscript
def __iter__(self) -> Iterator[Object]: ...
def __len__(self) -> int: ... # Tree_len
def __rtruediv__(self, other: str) -> Object: ...
def __truediv__(self, other: str) -> Object: ... # Tree_divide
def __rtruediv__(self, other: str) -> Tree | Blob: ...
def __truediv__(self, other: str) -> Tree | Blob: ... # Tree_divide

class TreeBuilder:
def clear(self) -> None: ...
Expand All @@ -1143,9 +1147,9 @@ class Worktree:
def prune(self, force=False) -> None: ...

def discover_repository(
path: str, across_fs: bool = False, ceiling_dirs: str = ...
path: str | Path, across_fs: bool = False, ceiling_dirs: str = ...
) -> str | None: ...
def hash(data: bytes) -> Oid: ...
def hash(data: bytes | str) -> Oid: ...
def hashfile(path: str) -> Oid: ...
def init_file_backend(path: str, flags: int = 0) -> object: ...
@overload
Expand Down Expand Up @@ -1207,7 +1211,7 @@ def option(
Option.DISABLE_PACK_KEEP_FILE_CHECKS,
Option.SET_OWNER_VALIDATION,
],
value: bool,
value: bool | Literal[0, 1],
) -> None: ...
@overload
def option(opt: Literal[Option.GET_OWNER_VALIDATION]) -> int: ...
Expand Down
30 changes: 17 additions & 13 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import platform
from pathlib import Path
from typing import Generator

import pytest

import pygit2
from pygit2 import Repository

from . import utils


@pytest.fixture(scope='session', autouse=True)
def global_git_config():
def global_git_config() -> None:
# Do not use global config for better test reproducibility.
# https://github.com/libgit2/pygit2/issues/989
levels = [
Expand All @@ -26,74 +28,76 @@ def global_git_config():


@pytest.fixture
def pygit2_empty_key():
def pygit2_empty_key() -> tuple[Path, str, str]:
path = Path(__file__).parent / 'keys' / 'pygit2_empty'
return path, f'{path}.pub', 'empty'


@pytest.fixture
def barerepo(tmp_path):
def barerepo(tmp_path: Path) -> Generator[Repository, None, None]:
with utils.TemporaryRepository('barerepo.zip', tmp_path) as path:
yield pygit2.Repository(path)


@pytest.fixture
def barerepo_path(tmp_path):
def barerepo_path(tmp_path: Path) -> Generator[tuple[Repository, Path], None, None]:
with utils.TemporaryRepository('barerepo.zip', tmp_path) as path:
yield pygit2.Repository(path), path


@pytest.fixture
def blameflagsrepo(tmp_path):
def blameflagsrepo(tmp_path: Path) -> Generator[Repository, None, None]:
with utils.TemporaryRepository('blameflagsrepo.zip', tmp_path) as path:
yield pygit2.Repository(path)


@pytest.fixture
def dirtyrepo(tmp_path):
def dirtyrepo(tmp_path: Path) -> Generator[Repository, None, None]:
with utils.TemporaryRepository('dirtyrepo.zip', tmp_path) as path:
yield pygit2.Repository(path)


@pytest.fixture
def emptyrepo(barerepo, tmp_path):
def emptyrepo(
barerepo: Repository, tmp_path: Path
) -> Generator[Repository, None, None]:
with utils.TemporaryRepository('emptyrepo.zip', tmp_path) as path:
repo = pygit2.Repository(path)
repo.remotes.create('origin', barerepo.path)
yield repo


@pytest.fixture
def encodingrepo(tmp_path):
def encodingrepo(tmp_path: Path) -> Generator[Repository, None, None]:
with utils.TemporaryRepository('encoding.zip', tmp_path) as path:
yield pygit2.Repository(path)


@pytest.fixture
def mergerepo(tmp_path):
def mergerepo(tmp_path: Path) -> Generator[Repository, None, None]:
with utils.TemporaryRepository('testrepoformerging.zip', tmp_path) as path:
yield pygit2.Repository(path)


@pytest.fixture
def testrepo(tmp_path):
def testrepo(tmp_path: Path) -> Generator[Repository, None, None]:
with utils.TemporaryRepository('testrepo.zip', tmp_path) as path:
yield pygit2.Repository(path)


@pytest.fixture
def testrepo_path(tmp_path):
def testrepo_path(tmp_path: Path) -> Generator[tuple[Repository, Path], None, None]:
with utils.TemporaryRepository('testrepo.zip', tmp_path) as path:
yield pygit2.Repository(path), path


@pytest.fixture
def testrepopacked(tmp_path):
def testrepopacked(tmp_path: Path) -> Generator[Repository, None, None]:
with utils.TemporaryRepository('testrepopacked.zip', tmp_path) as path:
yield pygit2.Repository(path)


@pytest.fixture
def gpgsigned(tmp_path):
def gpgsigned(tmp_path: Path) -> Generator[Repository, None, None]:
with utils.TemporaryRepository('gpgsigned.zip', tmp_path) as path:
yield pygit2.Repository(path)
7 changes: 3 additions & 4 deletions test/test_blame.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,11 @@ def test_blame_flags(blameflagsrepo: Repository) -> None:
def test_blame_with_invalid_index(testrepo: Repository) -> None:
blame = testrepo.blame(PATH)

def test():
with pytest.raises(IndexError):
blame[100000]
blame[-1]

with pytest.raises(IndexError):
test()
with pytest.raises(OverflowError):
blame[-1]


def test_blame_for_line(testrepo: Repository) -> None:
Expand Down
2 changes: 1 addition & 1 deletion test/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def test_create_blob(testrepo: Repository) -> None:
assert len(BLOB_NEW_CONTENT) == len(blob_buffer)
assert BLOB_NEW_CONTENT == blob_buffer

def set_content():
def set_content() -> None:
blob_buffer[:2] = b'hi'

with pytest.raises(TypeError):
Expand Down
22 changes: 11 additions & 11 deletions test/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,27 @@ def config(testrepo: Repository) -> Generator[object, None, None]:
pass


def test_config(config):
def test_config(config: Config) -> None:
assert config is not None


def test_global_config():
def test_global_config() -> None:
try:
assert Config.get_global_config() is not None
except IOError:
# There is no user config
pass


def test_system_config():
def test_system_config() -> None:
try:
assert Config.get_system_config() is not None
except IOError:
# There is no system config
pass


def test_new():
def test_new() -> None:
# Touch file
open(CONFIG_FILENAME, 'w').close()

Expand All @@ -81,7 +81,7 @@ def test_new():
assert config_read['core.editor'] == 'ed'


def test_add():
def test_add() -> None:
with open(CONFIG_FILENAME, 'w') as new_file:
new_file.write('[this]\n\tthat = true\n')
new_file.write('[something "other"]\n\there = false')
Expand All @@ -94,7 +94,7 @@ def test_add():
assert not config.get_bool('something.other.here')


def test_add_aspath():
def test_add_aspath() -> None:
with open(CONFIG_FILENAME, 'w') as new_file:
new_file.write('[this]\n\tthat = true\n')

Expand All @@ -103,7 +103,7 @@ def test_add_aspath():
assert 'this.that' in config


def test_read(config):
def test_read(config: Config) -> None:
with pytest.raises(TypeError):
config[()]
with pytest.raises(TypeError):
Expand All @@ -121,7 +121,7 @@ def test_read(config):
assert config.get_int('core.repositoryformatversion') == 0


def test_write(config):
def test_write(config: Config) -> None:
with pytest.raises(TypeError):
config.__setitem__((), 'This should not work')

Expand All @@ -148,7 +148,7 @@ def test_write(config):
assert 'core.dummy3' not in config


def test_multivar():
def test_multivar() -> None:
with open(CONFIG_FILENAME, 'w') as new_file:
new_file.write('[this]\n\tthat = foobar\n\tthat = foobeer\n')

Expand All @@ -175,7 +175,7 @@ def test_multivar():
assert [] == list(config.get_multivar('this.that', ''))


def test_iterator(config):
def test_iterator(config: Config) -> None:
lst = {}
for entry in config:
assert entry.level > -1
Expand All @@ -185,7 +185,7 @@ def test_iterator(config):
assert lst['core.bare']


def test_parsing():
def test_parsing() -> None:
assert Config.parse_bool('on')
assert Config.parse_bool('1')

Expand Down
32 changes: 22 additions & 10 deletions test/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,15 @@ def test_keypair_from_memory(
pygit2.clone_repository(url, tmp_path, callbacks=callbacks)


def test_callback(testrepo: Repository):
def test_callback(testrepo: Repository) -> None:
class MyCallbacks(pygit2.RemoteCallbacks):
def credentials(testrepo, url, username, allowed):
assert allowed & CredentialType.USERPASS_PLAINTEXT
def credentials(
self,
url: str,
username_from_url: str | None,
allowed_types: CredentialType,
) -> Username | UserPass | Keypair:
assert allowed_types & CredentialType.USERPASS_PLAINTEXT
raise Exception("I don't know the password")

url = 'https://github.com/github/github'
Expand All @@ -150,10 +155,15 @@ def credentials(testrepo, url, username, allowed):


@utils.requires_network
def test_bad_cred_type(testrepo: Repository):
def test_bad_cred_type(testrepo: Repository) -> None:
class MyCallbacks(pygit2.RemoteCallbacks):
def credentials(testrepo, url, username, allowed):
assert allowed & CredentialType.USERPASS_PLAINTEXT
def credentials(
self,
url: str,
username_from_url: str | None,
allowed_types: CredentialType,
) -> Username | UserPass | Keypair:
assert allowed_types & CredentialType.USERPASS_PLAINTEXT
return Keypair('git', 'foo.pub', 'foo', 'sekkrit')

url = 'https://github.com/github/github'
Expand All @@ -163,9 +173,11 @@ def credentials(testrepo, url, username, allowed):


@utils.requires_network
def test_fetch_certificate_check(testrepo: Repository):
def test_fetch_certificate_check(testrepo: Repository) -> None:
class MyCallbacks(pygit2.RemoteCallbacks):
def certificate_check(testrepo, certificate, valid, host):
def certificate_check(
self, certificate: None, valid: bool, host: bytes
) -> bool:
assert certificate is None
assert valid is True
assert host == b'github.com'
Expand All @@ -188,7 +200,7 @@ def certificate_check(testrepo, certificate, valid, host):


@utils.requires_network
def test_user_pass(testrepo: Repository):
def test_user_pass(testrepo: Repository) -> None:
credentials = UserPass('libgit2', 'libgit2')
callbacks = pygit2.RemoteCallbacks(credentials=credentials)

Expand All @@ -200,7 +212,7 @@ def test_user_pass(testrepo: Repository):
@utils.requires_proxy
@utils.requires_network
@utils.requires_future_libgit2
def test_proxy(testrepo: Repository):
def test_proxy(testrepo: Repository) -> None:
credentials = UserPass('libgit2', 'libgit2')
callbacks = pygit2.RemoteCallbacks(credentials=credentials)

Expand Down
Loading
Loading