From 55bc2861cdd014ee454c29cae2a1d6c7eec3312e Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 18:13:32 +0700 Subject: [PATCH 01/40] add some rules to ruff --- pyproject.toml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 20d4b61a..b5e4e2f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,18 @@ extend-exclude = [ "build", "venv*", ] +lint.select = ["C", "E", "W", "F", "I", "B", "C4", "ARG", "SIM", "PTH", "PL", "TID"] +lint.ignore = [ + "W291", # Trailing whitespace + "E501", # Line too long + "W293", # Blank line contains whitespace + "PLR0912", # Too many branches + "PLR2004", # Magic values + "PLR0915", # Too many statements + "PLW0603", # Global statement + "PLR0913", # Too many arguments + "B010", # setattr +] [tool.ruff.format] quote-style = "single" From 2c06530cf746e8d230b9c156e5187d84fd369859 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 18:28:48 +0700 Subject: [PATCH 02/40] ignore unused imports --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index b5e4e2f2..50c037af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,7 @@ lint.ignore = [ "PLW0603", # Global statement "PLR0913", # Too many arguments "B010", # setattr + "F401" # unused imports ] [tool.ruff.format] From 484886a335628d691bb971343e0699666f2b71b6 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 18:32:42 +0700 Subject: [PATCH 03/40] Initial formatting and liniting fix of all files --- build_tag.py | 3 +- pygit2/__init__.py | 26 +++++++++------- pygit2/_pygit2.pyi | 3 +- pygit2/_run.py | 2 +- pygit2/blame.py | 4 +-- pygit2/blob.py | 2 +- pygit2/branches.py | 3 +- pygit2/callbacks.py | 18 ++++-------- pygit2/config.py | 8 ++--- pygit2/credentials.py | 3 +- pygit2/errors.py | 7 ++--- pygit2/ffi.py | 3 +- pygit2/index.py | 9 +++--- pygit2/packbuilder.py | 2 +- pygit2/references.py | 1 + pygit2/refspec.py | 2 +- pygit2/remotes.py | 13 ++++---- pygit2/repository.py | 42 ++++++++++++++------------ pygit2/submodules.py | 7 +++-- pygit2/utils.py | 2 +- setup.py | 12 ++++---- test/conftest.py | 4 ++- test/test_apply_diff.py | 9 +++--- test/test_archive.py | 5 ++-- test/test_attributes.py | 2 +- test/test_blame.py | 5 ++-- test/test_blob.py | 38 ++++++++++++------------ test/test_branch.py | 7 +++-- test/test_branch_empty.py | 2 +- test/test_cherrypick.py | 1 + test/test_commit.py | 42 +++++++++++++------------- test/test_commit_gpg.py | 8 ++--- test/test_commit_trailer.py | 3 +- test/test_config.py | 30 +++++++++---------- test/test_credentials.py | 6 ++-- test/test_describe.py | 38 ++++++++++++------------ test/test_diff.py | 49 +++++++++++++++--------------- test/test_diff_binary.py | 8 ++--- test/test_filter.py | 27 +++++++++-------- test/test_index.py | 11 +++---- test/test_mailmap.py | 1 - test/test_merge.py | 26 ++++++++-------- test/test_note.py | 2 +- test/test_object.py | 5 ++-- test/test_odb.py | 8 ++--- test/test_odb_backend.py | 10 +++---- test/test_oid.py | 4 +-- test/test_packbuilder.py | 11 +++---- test/test_patch.py | 2 +- test/test_patch_encoding.py | 1 - test/test_refdb_backend.py | 3 +- test/test_refs.py | 32 ++++++++++++-------- test/test_remote.py | 54 +++++++++++++++++----------------- test/test_remote_utf8.py | 4 ++- test/test_repository.py | 36 +++++++++++------------ test/test_repository_bare.py | 35 +++++++++++----------- test/test_repository_custom.py | 3 +- test/test_revparse.py | 3 +- test/test_revwalk.py | 5 ++-- test/test_signature.py | 6 ++-- test/test_submodule.py | 15 +++++----- test/test_tag.py | 13 ++++---- test/test_tree.py | 10 +++---- test/utils.py | 3 +- 64 files changed, 391 insertions(+), 368 deletions(-) diff --git a/build_tag.py b/build_tag.py index 66c61b68..5051f997 100644 --- a/build_tag.py +++ b/build_tag.py @@ -1,4 +1,5 @@ -import platform, sys +import platform +import sys py = {'CPython': 'cp', 'PyPy': 'pp'}[platform.python_implementation()] print(f'{py}{sys.version_info.major}{sys.version_info.minor}') diff --git a/pygit2/__init__.py b/pygit2/__init__.py index 48857f96..e245184c 100644 --- a/pygit2/__init__.py +++ b/pygit2/__init__.py @@ -25,24 +25,31 @@ # Standard Library import functools -from os import PathLike import typing - -# Low level API -from ._pygit2 import * -from ._pygit2 import _cache_enums +from os import PathLike # High level API from . import enums from ._build import __version__ + +# Low level API +from ._pygit2 import * +from ._pygit2 import _cache_enums from .blame import Blame, BlameHunk from .blob import BlobIO -from .callbacks import Payload, RemoteCallbacks, CheckoutCallbacks, StashApplyCallbacks -from .callbacks import git_clone_options, git_fetch_options, get_credentials +from .callbacks import ( + CheckoutCallbacks, + Payload, + RemoteCallbacks, + StashApplyCallbacks, + get_credentials, + git_clone_options, + git_fetch_options, +) from .config import Config from .credentials import * -from .errors import check_error, Passthrough -from .ffi import ffi, C +from .errors import Passthrough, check_error +from .ffi import C, ffi from .filter import Filter from .index import Index, IndexEntry from .legacyenums import * @@ -53,7 +60,6 @@ from .submodules import Submodule from .utils import to_bytes, to_str - # Features features = enums.Feature(C.git_libgit2_features()) diff --git a/pygit2/_pygit2.pyi b/pygit2/_pygit2.pyi index a73da2a3..5c3c879c 100644 --- a/pygit2/_pygit2.pyi +++ b/pygit2/_pygit2.pyi @@ -1,5 +1,6 @@ -from typing import Iterator, Literal, Optional, overload from io import IOBase +from typing import Iterator, Literal, Optional, overload + from . import Index from .enums import ( ApplyLocation, diff --git a/pygit2/_run.py b/pygit2/_run.py index 78b52a29..94f99426 100644 --- a/pygit2/_run.py +++ b/pygit2/_run.py @@ -29,8 +29,8 @@ # Import from the Standard Library import codecs -from pathlib import Path import sys +from pathlib import Path # Import from cffi from cffi import FFI diff --git a/pygit2/blame.py b/pygit2/blame.py index 3b7ef748..8a156362 100644 --- a/pygit2/blame.py +++ b/pygit2/blame.py @@ -24,9 +24,9 @@ # Boston, MA 02110-1301, USA. # Import from pygit2 -from .ffi import ffi, C +from ._pygit2 import Oid, Signature +from .ffi import C, ffi from .utils import GenericIterator -from ._pygit2 import Signature, Oid def wrap_signature(csig): diff --git a/pygit2/blob.py b/pygit2/blob.py index d9f4de89..19e3f3c4 100644 --- a/pygit2/blob.py +++ b/pygit2/blob.py @@ -2,8 +2,8 @@ import threading import time from contextlib import AbstractContextManager -from typing import Optional from queue import Queue +from typing import Optional from ._pygit2 import Blob, Oid from .enums import BlobFilter diff --git a/pygit2/branches.py b/pygit2/branches.py index 99630d31..21d887ad 100644 --- a/pygit2/branches.py +++ b/pygit2/branches.py @@ -24,10 +24,11 @@ # Boston, MA 02110-1301, USA. from __future__ import annotations + from typing import TYPE_CHECKING -from .enums import BranchType, ReferenceType from ._pygit2 import Commit, Oid +from .enums import BranchType, ReferenceType # Need BaseRepository for type hints, but don't let it cause a circular dependency if TYPE_CHECKING: diff --git a/pygit2/callbacks.py b/pygit2/callbacks.py index a01268b6..5ebe475c 100644 --- a/pygit2/callbacks.py +++ b/pygit2/callbacks.py @@ -68,12 +68,11 @@ from typing import Optional, Union # pygit2 -from ._pygit2 import Oid, DiffFile +from ._pygit2 import DiffFile, Oid from .enums import CheckoutNotify, CheckoutStrategy, CredentialType, StashApplyProgress -from .errors import check_error, Passthrough -from .ffi import ffi, C -from .utils import maybe_string, to_bytes, ptr_to_bytes, StrArray - +from .errors import Passthrough, check_error +from .ffi import C, ffi +from .utils import StrArray, maybe_string, ptr_to_bytes, to_bytes # # The payload is the way to pass information from the pygit2 API, through @@ -471,9 +470,7 @@ def _certificate_check_cb(cert_i, valid, host, data): if not val: return C.GIT_ECERTIFICATE except Passthrough: - if is_ssh: - return 0 - elif valid: + if is_ssh or valid: return 0 else: return C.GIT_ECERTIFICATE @@ -669,10 +666,7 @@ def _git_checkout_options( paths=None, c_checkout_options_ptr=None, ): - if callbacks is None: - payload = CheckoutCallbacks() - else: - payload = callbacks + payload = CheckoutCallbacks() if callbacks is None else callbacks # Get handle to payload handle = ffi.new_handle(payload) diff --git a/pygit2/config.py b/pygit2/config.py index 8143a1f1..e5bce33b 100644 --- a/pygit2/config.py +++ b/pygit2/config.py @@ -29,8 +29,10 @@ from cached_property import cached_property # Import from pygit2 +import contextlib + from .errors import check_error -from .ffi import ffi, C +from .ffi import C, ffi from .utils import to_bytes @@ -96,10 +98,8 @@ def from_c(cls, repo, ptr): return config def __del__(self): - try: + with contextlib.suppress(AttributeError): C.git_config_free(self._config) - except AttributeError: - pass def _get(self, key): key = str_to_bytes(key, 'key') diff --git a/pygit2/credentials.py b/pygit2/credentials.py index fb5ae81e..f16aac4a 100644 --- a/pygit2/credentials.py +++ b/pygit2/credentials.py @@ -23,9 +23,8 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. -from .ffi import C - from .enums import CredentialType +from .ffi import C class Username: diff --git a/pygit2/errors.py b/pygit2/errors.py index d95bfaa6..53108072 100644 --- a/pygit2/errors.py +++ b/pygit2/errors.py @@ -24,11 +24,10 @@ # Boston, MA 02110-1301, USA. # Import from pygit2 -from .ffi import ffi, C from ._pygit2 import GitError +from .ffi import C, ffi - -value_errors = set([C.GIT_EEXISTS, C.GIT_EINVALIDSPEC, C.GIT_EAMBIGUOUS]) +value_errors = {C.GIT_EEXISTS, C.GIT_EINVALIDSPEC, C.GIT_EAMBIGUOUS} def check_error(err, io=False): @@ -36,7 +35,7 @@ def check_error(err, io=False): return # These are special error codes, they should never reach here - test = err != C.GIT_EUSER and err != C.GIT_PASSTHROUGH + test = err not in (C.GIT_EUSER, C.GIT_PASSTHROUGH) assert test, f'Unexpected error code {err}' # Error message diff --git a/pygit2/ffi.py b/pygit2/ffi.py index 7a60faf7..25814e0e 100644 --- a/pygit2/ffi.py +++ b/pygit2/ffi.py @@ -24,4 +24,5 @@ # Boston, MA 02110-1301, USA. # Import from pygit2 -from ._libgit2 import ffi, lib as C +from ._libgit2 import ffi +from ._libgit2 import lib as C diff --git a/pygit2/index.py b/pygit2/index.py index b06ae684..df164c0f 100644 --- a/pygit2/index.py +++ b/pygit2/index.py @@ -27,12 +27,11 @@ import weakref # Import from pygit2 -from ._pygit2 import Oid, Tree, Diff +from ._pygit2 import Diff, Oid, Tree from .enums import DiffOption, FileMode from .errors import check_error -from .ffi import ffi, C -from .utils import to_bytes, to_str -from .utils import GenericIterator, StrArray +from .ffi import C, ffi +from .utils import GenericIterator, StrArray, to_bytes, to_str class Index: @@ -367,7 +366,7 @@ def oid(self): @property def hex(self): """The id of the referenced object as a hex string""" - warnings.warn('Use str(entry.id)', DeprecationWarning) + warnings.warn('Use str(entry.id)', DeprecationWarning, stacklevel=2) return str(self.id) def __str__(self): diff --git a/pygit2/packbuilder.py b/pygit2/packbuilder.py index 0bee41ac..8fefcd89 100644 --- a/pygit2/packbuilder.py +++ b/pygit2/packbuilder.py @@ -26,7 +26,7 @@ # Import from pygit2 from .errors import check_error -from .ffi import ffi, C +from .ffi import C, ffi from .utils import to_bytes diff --git a/pygit2/references.py b/pygit2/references.py index f36d7be2..45784ca7 100644 --- a/pygit2/references.py +++ b/pygit2/references.py @@ -24,6 +24,7 @@ # Boston, MA 02110-1301, USA. from __future__ import annotations + from typing import TYPE_CHECKING from .enums import ReferenceFilter diff --git a/pygit2/refspec.py b/pygit2/refspec.py index 423d820a..0af6aa73 100644 --- a/pygit2/refspec.py +++ b/pygit2/refspec.py @@ -25,7 +25,7 @@ # Import from pygit2 from .errors import check_error -from .ffi import ffi, C +from .ffi import C, ffi from .utils import to_bytes diff --git a/pygit2/remotes.py b/pygit2/remotes.py index 02a4dbe2..b26bc917 100644 --- a/pygit2/remotes.py +++ b/pygit2/remotes.py @@ -24,17 +24,19 @@ # Boston, MA 02110-1301, USA. from __future__ import annotations + from typing import TYPE_CHECKING +from . import utils + # Import from pygit2 from ._pygit2 import Oid from .callbacks import git_fetch_options, git_push_options, git_remote_callbacks from .enums import FetchPrune from .errors import check_error -from .ffi import ffi, C +from .ffi import C, ffi from .refspec import Refspec -from . import utils -from .utils import maybe_string, to_bytes, strarray_to_strings, StrArray +from .utils import StrArray, maybe_string, strarray_to_strings, to_bytes # Need BaseRepository for type hints, but don't let it cause a circular dependency if TYPE_CHECKING: @@ -185,10 +187,7 @@ def ls_remotes(self, callbacks=None, proxy=None): for i in range(int(refs_len[0])): ref = refs[0][i] local = bool(ref.local) - if local: - loid = Oid(raw=bytes(ffi.buffer(ref.loid.id)[:])) - else: - loid = None + loid = Oid(raw=bytes(ffi.buffer(ref.loid.id)[:])) if local else None remote = { 'local': local, diff --git a/pygit2/repository.py b/pygit2/repository.py index 38a969d3..fb2d7038 100644 --- a/pygit2/repository.py +++ b/pygit2/repository.py @@ -23,19 +23,28 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. +import tarfile +import typing from io import BytesIO from os import PathLike from string import hexdigits from time import time -import tarfile -import typing -# Import from pygit2 -from ._pygit2 import Repository as _Repository, init_file_backend -from ._pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN -from ._pygit2 import Reference, Tree, Commit, Blob, Signature -from ._pygit2 import InvalidSpecError +from ._pygit2 import ( + GIT_OID_HEXSZ, + GIT_OID_MINPREFIXLEN, + Blob, + Commit, + InvalidSpecError, + Oid, + Reference, + Signature, + Tree, + init_file_backend, +) +# Import from pygit2 +from ._pygit2 import Repository as _Repository from .blame import Blame from .branches import Branches from .callbacks import git_checkout_options, git_stash_apply_options @@ -56,13 +65,13 @@ RepositoryState, ) from .errors import check_error -from .ffi import ffi, C +from .ffi import C, ffi from .index import Index, IndexEntry from .packbuilder import PackBuilder from .references import References from .remotes import RemoteCollection from .submodules import SubmoduleCollection -from .utils import to_bytes, StrArray +from .utils import StrArray, to_bytes class BaseRepository(_Repository): @@ -167,10 +176,7 @@ def hashfile( """ c_path = to_bytes(path) - if as_path is None: - c_as_path = ffi.NULL - else: - c_as_path = to_bytes(as_path) + c_as_path = ffi.NULL if as_path is None else to_bytes(as_path) c_oid = ffi.new('git_oid *') @@ -271,11 +277,11 @@ def create_reference(self, name, target, force=False, message=None): def listall_references(self) -> typing.List[str]: """Return a list with all the references in the repository.""" - return list(x.name for x in self.references.iterator()) + return [x.name for x in self.references.iterator()] def listall_reference_objects(self) -> typing.List[Reference]: """Return a list with all the reference objects in the repository.""" - return list(x for x in self.references.iterator()) + return list(self.references.iterator()) def resolve_refish(self, refish): """Convert a reference-like short name "ref-ish" to a valid @@ -435,7 +441,7 @@ def __whatever_to_tree_or_blob(self, obj): return None # If it's a string, then it has to be valid revspec - if isinstance(obj, str) or isinstance(obj, bytes): + if isinstance(obj, (str, bytes)): obj = self.revparse_single(obj) elif isinstance(obj, Oid): obj = self[obj] @@ -527,7 +533,7 @@ def diff( # Case 1: Diff tree to tree if isinstance(a, Tree) and isinstance(b, Tree): - return a.diff_to_tree(b, **dict(zip(opt_keys, opt_values))) + return a.diff_to_tree(b, **dict(zip(opt_keys, opt_values, strict=False))) # Case 2: Index to workdir elif a is None and b is None: @@ -1370,7 +1376,7 @@ def get_attr( elif attr_kind == C.GIT_ATTR_VALUE_STRING: return ffi.string(cvalue[0]).decode('utf-8') - assert False, 'the attribute value from libgit2 is invalid' + raise AssertionError('the attribute value from libgit2 is invalid') # # Identity for reference operations diff --git a/pygit2/submodules.py b/pygit2/submodules.py index 08b1a9a5..257ef00c 100644 --- a/pygit2/submodules.py +++ b/pygit2/submodules.py @@ -24,14 +24,15 @@ # Boston, MA 02110-1301, USA. from __future__ import annotations + from typing import TYPE_CHECKING, Iterable, Iterator, Optional, Union from ._pygit2 import Oid -from .callbacks import git_fetch_options, RemoteCallbacks +from .callbacks import RemoteCallbacks, git_fetch_options from .enums import SubmoduleIgnore, SubmoduleStatus from .errors import check_error -from .ffi import ffi, C -from .utils import to_bytes, maybe_string +from .ffi import C, ffi +from .utils import maybe_string, to_bytes # Need BaseRepository for type hints, but don't let it cause a circular dependency if TYPE_CHECKING: diff --git a/pygit2/utils.py b/pygit2/utils.py index 0660cc42..bf6d7ead 100644 --- a/pygit2/utils.py +++ b/pygit2/utils.py @@ -27,7 +27,7 @@ import os # Import from pygit2 -from .ffi import ffi, C +from .ffi import C, ffi def maybe_string(ptr): diff --git a/setup.py b/setup.py index 7c158eff..7751bdfc 100644 --- a/setup.py +++ b/setup.py @@ -24,15 +24,15 @@ # Boston, MA 02110-1301, USA. # Import setuptools before distutils to avoid user warning -from setuptools import setup, Extension - +import os +import sys +from distutils import log from distutils.command.build import build from distutils.command.sdist import sdist -from distutils import log -import os from pathlib import Path -from subprocess import Popen, PIPE -import sys +from subprocess import PIPE, Popen + +from setuptools import Extension, setup # Import stuff from pygit2/_utils.py without loading the whole pygit2 package sys.path.insert(0, 'pygit2') diff --git a/test/conftest.py b/test/conftest.py index 1c6d7b8f..6feb9d23 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,8 +1,10 @@ -from pathlib import Path import platform +from pathlib import Path import pytest + import pygit2 + from . import utils diff --git a/test/test_apply_diff.py b/test/test_apply_diff.py index 915d4368..7dc6da16 100644 --- a/test/test_apply_diff.py +++ b/test/test_apply_diff.py @@ -23,13 +23,14 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. -import pygit2 -from pygit2.enums import ApplyLocation, CheckoutStrategy, FileStatus -import pytest - import os from pathlib import Path +import pytest + +import pygit2 +from pygit2.enums import ApplyLocation, CheckoutStrategy, FileStatus + def read_content(testrepo): with (Path(testrepo.workdir) / 'hello.txt').open('rb') as f: diff --git a/test/test_archive.py b/test/test_archive.py index b6977714..bb41bc22 100644 --- a/test/test_archive.py +++ b/test/test_archive.py @@ -23,11 +23,10 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. -from pathlib import Path import tarfile +from pathlib import Path -from pygit2 import Index, Oid, Tree, Object - +from pygit2 import Index, Object, Oid, Tree TREE_HASH = 'fd937514cb799514d4b81bb24c5fcfeb6472b245' COMMIT_HASH = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98' diff --git a/test/test_attributes.py b/test/test_attributes.py index 73b0cbe4..f5df0c6b 100644 --- a/test/test_attributes.py +++ b/test/test_attributes.py @@ -38,7 +38,7 @@ def test_no_attr(testrepo): assert testrepo.get_attr('file.py', 'foo') is None assert testrepo.get_attr('file.py', 'text') assert not testrepo.get_attr('file.jpg', 'text') - assert 'lf' == testrepo.get_attr('file.sh', 'eol') + assert testrepo.get_attr('file.sh', 'eol') == 'lf' def test_no_attr_aspath(testrepo): diff --git a/test/test_blame.py b/test/test_blame.py index 8bd7fca3..e0a6a2d1 100644 --- a/test/test_blame.py +++ b/test/test_blame.py @@ -27,10 +27,9 @@ import pytest -from pygit2 import Signature, Oid +from pygit2 import Oid, Signature from pygit2.enums import BlameFlag - PATH = 'hello.txt' HUNKS = [ @@ -109,7 +108,7 @@ def test(): def test_blame_for_line(testrepo): blame = testrepo.blame(PATH) - for i, line in zip(range(0, 2), range(1, 3)): + for i, line in zip(range(0, 2), range(1, 3), strict=False): hunk = blame.for_line(line) assert hunk.lines_in_hunk == 1 diff --git a/test/test_blob.py b/test/test_blob.py index 78cec628..afec399c 100644 --- a/test/test_blob.py +++ b/test/test_blob.py @@ -27,15 +27,15 @@ import io from pathlib import Path -from threading import Event from queue import Queue +from threading import Event import pytest import pygit2 from pygit2.enums import ObjectType -from . import utils +from . import utils BLOB_SHA = 'a520c24d85fbfc815d385957eed41406ca5a860b' BLOB_CONTENT = """hello world @@ -86,10 +86,10 @@ def test_read_blob(testrepo): assert blob.id == BLOB_SHA assert isinstance(blob, pygit2.Blob) assert not blob.is_binary - assert ObjectType.BLOB == blob.type - assert BLOB_CONTENT == blob.data + assert blob.type == ObjectType.BLOB + assert blob.data == BLOB_CONTENT assert len(BLOB_CONTENT) == blob.size - assert BLOB_CONTENT == blob.read_raw() + assert blob.read_raw() == BLOB_CONTENT def test_create_blob(testrepo): @@ -97,17 +97,17 @@ def test_create_blob(testrepo): blob = testrepo[blob_oid] assert isinstance(blob, pygit2.Blob) - assert ObjectType.BLOB == blob.type + assert blob.type == ObjectType.BLOB assert blob_oid == blob.id assert utils.gen_blob_sha1(BLOB_NEW_CONTENT) == blob_oid - assert BLOB_NEW_CONTENT == blob.data + assert blob.data == BLOB_NEW_CONTENT assert len(BLOB_NEW_CONTENT) == blob.size - assert BLOB_NEW_CONTENT == blob.read_raw() + assert blob.read_raw() == BLOB_NEW_CONTENT blob_buffer = memoryview(blob) assert len(BLOB_NEW_CONTENT) == len(blob_buffer) - assert BLOB_NEW_CONTENT == blob_buffer + assert blob_buffer == BLOB_NEW_CONTENT def set_content(): blob_buffer[:2] = b'hi' @@ -121,14 +121,14 @@ def test_create_blob_fromworkdir(testrepo): blob = testrepo[blob_oid] assert isinstance(blob, pygit2.Blob) - assert ObjectType.BLOB == blob.type + assert blob.type == ObjectType.BLOB assert blob_oid == blob.id assert utils.gen_blob_sha1(BLOB_FILE_CONTENT) == blob_oid - assert BLOB_FILE_CONTENT == blob.data + assert blob.data == BLOB_FILE_CONTENT assert len(BLOB_FILE_CONTENT) == blob.size - assert BLOB_FILE_CONTENT == blob.read_raw() + assert blob.read_raw() == BLOB_FILE_CONTENT def test_create_blob_fromworkdir_aspath(testrepo): @@ -148,7 +148,7 @@ def test_create_blob_fromdisk(testrepo): blob = testrepo[blob_oid] assert isinstance(blob, pygit2.Blob) - assert ObjectType.BLOB == blob.type + assert blob.type == ObjectType.BLOB def test_create_blob_fromiobase(testrepo): @@ -160,10 +160,10 @@ def test_create_blob_fromiobase(testrepo): blob = testrepo[blob_oid] assert isinstance(blob, pygit2.Blob) - assert ObjectType.BLOB == blob.type + assert blob.type == ObjectType.BLOB assert blob_oid == blob.id - assert BLOB_SHA == blob_oid + assert blob_oid == BLOB_SHA def test_diff_blob(testrepo): @@ -220,7 +220,7 @@ def test_blob_write_to_queue(testrepo): chunks = [] while not queue.empty(): chunks.append(queue.get()) - assert BLOB_CONTENT == b''.join(chunks) + assert b''.join(chunks) == BLOB_CONTENT def test_blob_write_to_queue_filtered(testrepo): @@ -235,14 +235,14 @@ def test_blob_write_to_queue_filtered(testrepo): chunks = [] while not queue.empty(): chunks.append(queue.get()) - assert b'bye world\n' == b''.join(chunks) + assert b''.join(chunks) == b'bye world\n' def test_blobio(testrepo): blob_oid = testrepo.create_blob_fromworkdir('bye.txt') blob = testrepo[blob_oid] with pygit2.BlobIO(blob) as reader: - assert b'bye world\n' == reader.read() + assert reader.read() == b'bye world\n' assert not reader.raw._thread.is_alive() @@ -250,5 +250,5 @@ def test_blobio_filtered(testrepo): blob_oid = testrepo.create_blob_fromworkdir('bye.txt') blob = testrepo[blob_oid] with pygit2.BlobIO(blob, as_path='bye.txt') as reader: - assert b'bye world\n' == reader.read() + assert reader.read() == b'bye world\n' assert not reader.raw._thread.is_alive() diff --git a/test/test_branch.py b/test/test_branch.py index 4f4903a4..82f7799c 100644 --- a/test/test_branch.py +++ b/test/test_branch.py @@ -25,11 +25,12 @@ """Tests for branch methods.""" -import pygit2 -import pytest import os -from pygit2.enums import BranchType +import pytest + +import pygit2 +from pygit2.enums import BranchType LAST_COMMIT = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98' I18N_LAST_COMMIT = '5470a671a80ac3789f1a6a8cefbcf43ce7af0563' diff --git a/test/test_branch_empty.py b/test/test_branch_empty.py index 2afd749f..fe33f812 100644 --- a/test/test_branch_empty.py +++ b/test/test_branch_empty.py @@ -24,8 +24,8 @@ # Boston, MA 02110-1301, USA. import pytest -from pygit2.enums import BranchType +from pygit2.enums import BranchType ORIGIN_MASTER_COMMIT = '784855caf26449a1914d2cf62d12b9374d76ae78' diff --git a/test/test_cherrypick.py b/test/test_cherrypick.py index a5e5c558..5d6da70c 100644 --- a/test/test_cherrypick.py +++ b/test/test_cherrypick.py @@ -26,6 +26,7 @@ """Tests for merging and information about it.""" from pathlib import Path + import pytest import pygit2 diff --git a/test/test_commit.py b/test/test_commit.py index 521059b9..b3254128 100644 --- a/test/test_commit.py +++ b/test/test_commit.py @@ -29,10 +29,10 @@ import pytest -from pygit2 import Signature, Oid, GitError +from pygit2 import GitError, Oid, Signature from pygit2.enums import ObjectType -from . import utils +from . import utils COMMIT_SHA = '5fe808e8953c12735680c257f56600cb0de44b10' COMMIT_SHA_TO_AMEND = ( @@ -52,10 +52,10 @@ def test_commit_refcount(barerepo): def test_read_commit(barerepo): commit = barerepo[COMMIT_SHA] - assert COMMIT_SHA == commit.id + assert commit.id == COMMIT_SHA parents = commit.parents - assert 1 == len(parents) - assert 'c2792cfa289ae6321ecf2cd5806c2194b0fd070c' == parents[0].id + assert len(parents) == 1 + assert parents[0].id == 'c2792cfa289ae6321ecf2cd5806c2194b0fd070c' assert commit.message_encoding is None assert commit.message == ( 'Second test data commit.\n\n' 'This commit has some additional text.\n' @@ -68,7 +68,7 @@ def test_read_commit(barerepo): assert commit.author == Signature( 'Dave Borowitz', 'dborowitz@google.com', 1288477363, -420 ) - assert '967fce8df97cc71722d3c2a5930ef3e6f1d27b12' == commit.tree.id + assert commit.tree.id == '967fce8df97cc71722d3c2a5930ef3e6f1d27b12' def test_new_commit(barerepo): @@ -89,17 +89,17 @@ def test_new_commit(barerepo): sha = repo.create_commit(None, author, committer, message, tree_prefix, parents) commit = repo[sha] - assert ObjectType.COMMIT == commit.type - assert '98286caaab3f1fde5bf52c8369b2b0423bad743b' == commit.id + assert commit.type == ObjectType.COMMIT + assert commit.id == '98286caaab3f1fde5bf52c8369b2b0423bad743b' assert commit.message_encoding is None assert message == commit.message - assert 12346 == commit.commit_time + assert commit.commit_time == 12346 assert committer == commit.committer assert author == commit.author assert tree == commit.tree.id assert Oid(hex=tree) == commit.tree_id - assert 1 == len(commit.parents) - assert COMMIT_SHA == commit.parents[0].id + assert len(commit.parents) == 1 + assert commit.parents[0].id == COMMIT_SHA assert Oid(hex=COMMIT_SHA) == commit.parent_ids[0] @@ -118,16 +118,16 @@ def test_new_commit_encoding(barerepo): ) commit = repo[sha] - assert ObjectType.COMMIT == commit.type - assert 'iso-8859-1' == commit.message_encoding + assert commit.type == ObjectType.COMMIT + assert commit.message_encoding == 'iso-8859-1' assert message.encode(encoding) == commit.raw_message - assert 12346 == commit.commit_time + assert commit.commit_time == 12346 assert committer == commit.committer assert author == commit.author assert tree == commit.tree.id assert Oid(hex=tree) == commit.tree_id - assert 1 == len(commit.parents) - assert COMMIT_SHA == commit.parents[0].id + assert len(commit.parents) == 1 + assert commit.parents[0].id == COMMIT_SHA assert Oid(hex=COMMIT_SHA) == commit.parent_ids[0] @@ -175,7 +175,7 @@ def test_amend_commit_metadata(barerepo): amended_commit = repo[amended_oid] assert repo.head.target == amended_oid - assert ObjectType.COMMIT == amended_commit.type + assert amended_commit.type == ObjectType.COMMIT assert amended_committer == amended_commit.committer assert amended_author == amended_commit.author assert amended_message.encode(encoding) == amended_commit.raw_message @@ -196,7 +196,7 @@ def test_amend_commit_tree(barerepo): amended_commit = repo[amended_oid] assert repo.head.target == amended_oid - assert ObjectType.COMMIT == amended_commit.type + assert amended_commit.type == ObjectType.COMMIT assert commit.message == amended_commit.message assert commit.author == amended_commit.author assert commit.committer == amended_commit.committer @@ -267,13 +267,13 @@ def test_amend_commit_argument_types(barerepo): # Pass an Oid for the commit amended_oid = repo.amend_commit(alt_commit1, None, message='Hello') amended_commit = repo[amended_oid] - assert ObjectType.COMMIT == amended_commit.type + assert amended_commit.type == ObjectType.COMMIT assert amended_oid != COMMIT_SHA_TO_AMEND # Pass a str for the commit amended_oid = repo.amend_commit(alt_commit2, None, message='Hello', tree=alt_tree) amended_commit = repo[amended_oid] - assert ObjectType.COMMIT == amended_commit.type + assert amended_commit.type == ObjectType.COMMIT assert amended_oid != COMMIT_SHA_TO_AMEND assert repo[COMMIT_SHA_TO_AMEND].tree != amended_commit.tree assert alt_tree.id == amended_commit.tree_id @@ -282,6 +282,6 @@ def test_amend_commit_argument_types(barerepo): # (Warning: the tip of the branch will be altered after this test!) amended_oid = repo.amend_commit(alt_commit2, alt_refname, message='Hello') amended_commit = repo[amended_oid] - assert ObjectType.COMMIT == amended_commit.type + assert amended_commit.type == ObjectType.COMMIT assert amended_oid != COMMIT_SHA_TO_AMEND assert repo.head.target == amended_oid diff --git a/test/test_commit_gpg.py b/test/test_commit_gpg.py index cb1c812e..58675639 100644 --- a/test/test_commit_gpg.py +++ b/test/test_commit_gpg.py @@ -119,16 +119,16 @@ def test_commit_signing(gpgsigned): assert gpgsig_content == commit.read_raw().decode('utf-8') # perform sanity checks - assert ObjectType.COMMIT == commit.type - assert '6569fdf71dbd99081891154641869c537784a3ba' == commit.id + assert commit.type == ObjectType.COMMIT + assert commit.id == '6569fdf71dbd99081891154641869c537784a3ba' assert commit.message_encoding is None assert message == commit.message - assert 1358451456 == commit.commit_time + assert commit.commit_time == 1358451456 assert committer == commit.committer assert author == commit.author assert tree == commit.tree.id assert Oid(hex=tree) == commit.tree_id - assert 1 == len(commit.parents) + assert len(commit.parents) == 1 assert parent == commit.parents[0].id assert Oid(hex=parent) == commit.parent_ids[0] diff --git a/test/test_commit_trailer.py b/test/test_commit_trailer.py index 7f07825e..b176122d 100644 --- a/test/test_commit_trailer.py +++ b/test/test_commit_trailer.py @@ -23,9 +23,10 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. -import pygit2 import pytest +import pygit2 + from . import utils diff --git a/test/test_config.py b/test/test_config.py index c89c7d38..06e5a8a2 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -23,13 +23,14 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. +import contextlib from pathlib import Path import pytest from pygit2 import Config -from . import utils +from . import utils CONFIG_FILENAME = 'test_config' @@ -37,10 +38,8 @@ @pytest.fixture def config(testrepo): yield testrepo.config - try: + with contextlib.suppress(OSError): Path(CONFIG_FILENAME).unlink() - except OSError: - pass def test_config(config): @@ -155,23 +154,24 @@ def test_multivar(): config.add_file(CONFIG_FILENAME, 6) assert 'this.that' in config - assert ['foobar', 'foobeer'] == list(config.get_multivar('this.that')) - assert ['foobar'] == list(config.get_multivar('this.that', 'bar')) - assert ['foobar', 'foobeer'] == list(config.get_multivar('this.that', 'foo.*')) + assert list(config.get_multivar('this.that')) == ['foobar', 'foobeer'] + assert list(config.get_multivar('this.that', 'bar')) == ['foobar'] + assert list(config.get_multivar('this.that', 'foo.*')) == ['foobar', 'foobeer'] config.set_multivar('this.that', '^.*beer', 'fool') - assert ['fool'] == list(config.get_multivar('this.that', 'fool')) + assert list(config.get_multivar('this.that', 'fool')) == ['fool'] config.set_multivar('this.that', 'foo.*', 'foo-123456') - assert ['foo-123456', 'foo-123456'] == list( - config.get_multivar('this.that', 'foo.*') - ) + assert list(config.get_multivar('this.that', 'foo.*')) == [ + 'foo-123456', + 'foo-123456', + ] config.delete_multivar('this.that', 'bar') - assert ['foo-123456', 'foo-123456'] == list(config.get_multivar('this.that', '')) + assert list(config.get_multivar('this.that', '')) == ['foo-123456', 'foo-123456'] config.delete_multivar('this.that', 'foo-[0-9]+') - assert [] == list(config.get_multivar('this.that', '')) + assert list(config.get_multivar('this.that', '')) == [] def test_iterator(config): @@ -188,5 +188,5 @@ def test_parsing(): assert Config.parse_bool('on') assert Config.parse_bool('1') - assert 5 == Config.parse_int('5') - assert 1024 == Config.parse_int('1k') + assert Config.parse_int('5') == 5 + assert Config.parse_int('1k') == 1024 diff --git a/test/test_credentials.py b/test/test_credentials.py index 0e9adf66..90b870d3 100644 --- a/test/test_credentials.py +++ b/test/test_credentials.py @@ -25,16 +25,16 @@ """Tests for credentials""" -from pathlib import Path import platform +from pathlib import Path import pytest import pygit2 -from pygit2 import Username, UserPass, Keypair, KeypairFromAgent, KeypairFromMemory +from pygit2 import Keypair, KeypairFromAgent, KeypairFromMemory, Username, UserPass from pygit2.enums import CredentialType -from . import utils +from . import utils REMOTE_NAME = 'origin' REMOTE_URL = 'git://github.com/libgit2/pygit2.git' diff --git a/test/test_describe.py b/test/test_describe.py index 7ae41c28..65a2b02a 100644 --- a/test/test_describe.py +++ b/test/test_describe.py @@ -27,8 +27,8 @@ import pytest -from pygit2.enums import DescribeStrategy, ObjectType import pygit2 +from pygit2.enums import DescribeStrategy, ObjectType def add_tag(repo, name, target): @@ -41,7 +41,7 @@ def add_tag(repo, name, target): def test_describe(testrepo): add_tag(testrepo, 'thetag', '4ec4389a8068641da2d6578db0419484972284c8') - assert 'thetag-2-g2be5719' == testrepo.describe() + assert testrepo.describe() == 'thetag-2-g2be5719' def test_describe_without_ref(testrepo): @@ -50,19 +50,20 @@ def test_describe_without_ref(testrepo): def test_describe_default_oid(testrepo): - assert '2be5719' == testrepo.describe(show_commit_oid_as_fallback=True) + assert testrepo.describe(show_commit_oid_as_fallback=True) == '2be5719' def test_describe_strategies(testrepo): - assert 'heads/master' == testrepo.describe(describe_strategy=DescribeStrategy.ALL) + assert testrepo.describe(describe_strategy=DescribeStrategy.ALL) == 'heads/master' testrepo.create_reference( 'refs/tags/thetag', '4ec4389a8068641da2d6578db0419484972284c8' ) with pytest.raises(KeyError): testrepo.describe() - assert 'thetag-2-g2be5719' == testrepo.describe( - describe_strategy=DescribeStrategy.TAGS + assert ( + testrepo.describe(describe_strategy=DescribeStrategy.TAGS) + == 'thetag-2-g2be5719' ) @@ -70,20 +71,21 @@ def test_describe_pattern(testrepo): add_tag(testrepo, 'private/tag1', '5ebeeebb320790caf276b9fc8b24546d63316533') add_tag(testrepo, 'public/tag2', '4ec4389a8068641da2d6578db0419484972284c8') - assert 'public/tag2-2-g2be5719' == testrepo.describe(pattern='public/*') + assert testrepo.describe(pattern='public/*') == 'public/tag2-2-g2be5719' def test_describe_committish(testrepo): add_tag(testrepo, 'thetag', 'acecd5ea2924a4b900e7e149496e1f4b57976e51') - assert 'thetag-4-g2be5719' == testrepo.describe(committish='HEAD') - assert 'thetag-1-g5ebeeeb' == testrepo.describe(committish='HEAD^') + assert testrepo.describe(committish='HEAD') == 'thetag-4-g2be5719' + assert testrepo.describe(committish='HEAD^') == 'thetag-1-g5ebeeeb' - assert 'thetag-4-g2be5719' == testrepo.describe(committish=testrepo.head) + assert testrepo.describe(committish=testrepo.head) == 'thetag-4-g2be5719' - assert 'thetag-1-g6aaa262' == testrepo.describe( - committish='6aaa262e655dd54252e5813c8e5acd7780ed097d' + assert ( + testrepo.describe(committish='6aaa262e655dd54252e5813c8e5acd7780ed097d') + == 'thetag-1-g6aaa262' ) - assert 'thetag-1-g6aaa262' == testrepo.describe(committish='6aaa262') + assert testrepo.describe(committish='6aaa262') == 'thetag-1-g6aaa262' def test_describe_follows_first_branch_only(testrepo): @@ -94,20 +96,20 @@ def test_describe_follows_first_branch_only(testrepo): def test_describe_abbreviated_size(testrepo): add_tag(testrepo, 'thetag', '4ec4389a8068641da2d6578db0419484972284c8') - assert 'thetag-2-g2be5719152d4f82c' == testrepo.describe(abbreviated_size=16) - assert 'thetag' == testrepo.describe(abbreviated_size=0) + assert testrepo.describe(abbreviated_size=16) == 'thetag-2-g2be5719152d4f82c' + assert testrepo.describe(abbreviated_size=0) == 'thetag' def test_describe_long_format(testrepo): add_tag(testrepo, 'thetag', '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98') - assert 'thetag-0-g2be5719' == testrepo.describe(always_use_long_format=True) + assert testrepo.describe(always_use_long_format=True) == 'thetag-0-g2be5719' def test_describe_dirty(dirtyrepo): add_tag(dirtyrepo, 'thetag', 'a763aa560953e7cfb87ccbc2f536d665aa4dff22') - assert 'thetag' == dirtyrepo.describe() + assert dirtyrepo.describe() == 'thetag' def test_describe_dirty_with_suffix(dirtyrepo): add_tag(dirtyrepo, 'thetag', 'a763aa560953e7cfb87ccbc2f536d665aa4dff22') - assert 'thetag-dirty' == dirtyrepo.describe(dirty_suffix='-dirty') + assert dirtyrepo.describe(dirty_suffix='-dirty') == 'thetag-dirty' diff --git a/test/test_diff.py b/test/test_diff.py index b2138526..869fc3ec 100644 --- a/test/test_diff.py +++ b/test/test_diff.py @@ -25,15 +25,14 @@ """Tests for Diff objects.""" -from itertools import chain import textwrap +from itertools import chain import pytest import pygit2 from pygit2.enums import DeltaStatus, DiffFlag, DiffOption, DiffStatsFormat, FileMode - COMMIT_SHA1_1 = '5fe808e8953c12735680c257f56600cb0de44b10' COMMIT_SHA1_2 = 'c2792cfa289ae6321ecf2cd5806c2194b0fd070c' COMMIT_SHA1_3 = '2cdae28389c059815e951d0bb9eed6533f61a46b' @@ -114,11 +113,11 @@ def test_diff_empty_index(dirtyrepo): diff = head.tree.diff_to_index(repo.index) files = [patch.delta.new_file.path for patch in diff] - assert DIFF_HEAD_TO_INDEX_EXPECTED == files + assert files == DIFF_HEAD_TO_INDEX_EXPECTED diff = repo.diff('HEAD', cached=True) files = [patch.delta.new_file.path for patch in diff] - assert DIFF_HEAD_TO_INDEX_EXPECTED == files + assert files == DIFF_HEAD_TO_INDEX_EXPECTED def test_workdir_to_tree(dirtyrepo): @@ -127,17 +126,17 @@ def test_workdir_to_tree(dirtyrepo): diff = head.tree.diff_to_workdir() files = [patch.delta.new_file.path for patch in diff] - assert DIFF_HEAD_TO_WORKDIR_EXPECTED == files + assert files == DIFF_HEAD_TO_WORKDIR_EXPECTED diff = repo.diff('HEAD') files = [patch.delta.new_file.path for patch in diff] - assert DIFF_HEAD_TO_WORKDIR_EXPECTED == files + assert files == DIFF_HEAD_TO_WORKDIR_EXPECTED def test_index_to_workdir(dirtyrepo): diff = dirtyrepo.diff() files = [patch.delta.new_file.path for patch in diff] - assert DIFF_INDEX_TO_WORK_EXPECTED == files + assert files == DIFF_INDEX_TO_WORK_EXPECTED def test_diff_invalid(barerepo): @@ -172,7 +171,7 @@ def test_diff_tree(barerepo): def _test(diff): assert diff is not None - assert 2 == sum(map(lambda x: len(x.hunks), diff)) + assert sum((len(x.hunks) for x in diff)) == 2 patch = diff[0] hunk = patch.hunks[0] @@ -204,18 +203,18 @@ def test_diff_empty_tree(barerepo): diff = commit_a.tree.diff_to_tree() def get_context_for_lines(diff): - hunks = chain.from_iterable(map(lambda x: x.hunks, diff)) - lines = chain.from_iterable(map(lambda x: x.lines, hunks)) - return map(lambda x: x.origin, lines) + hunks = chain.from_iterable((x.hunks for x in diff)) + lines = chain.from_iterable((x.lines for x in hunks)) + return (x.origin for x in lines) entries = [p.delta.new_file.path for p in diff] assert all(commit_a.tree[x] for x in entries) - assert all('-' == x for x in get_context_for_lines(diff)) + assert all(x == '-' for x in get_context_for_lines(diff)) diff_swaped = commit_a.tree.diff_to_tree(swap=True) entries = [p.delta.new_file.path for p in diff_swaped] assert all(commit_a.tree[x] for x in entries) - assert all('+' == x for x in get_context_for_lines(diff_swaped)) + assert all(x == '+' for x in get_context_for_lines(diff_swaped)) def test_diff_revparse(barerepo): @@ -230,11 +229,11 @@ def test_diff_tree_opts(barerepo): for flag in [DiffOption.IGNORE_WHITESPACE, DiffOption.IGNORE_WHITESPACE_EOL]: diff = commit_c.tree.diff_to_tree(commit_d.tree, flag) assert diff is not None - assert 0 == len(diff[0].hunks) + assert len(diff[0].hunks) == 0 diff = commit_c.tree.diff_to_tree(commit_d.tree) assert diff is not None - assert 1 == len(diff[0].hunks) + assert len(diff[0].hunks) == 1 def test_diff_merge(barerepo): @@ -270,7 +269,7 @@ def test_diff_patch(barerepo): diff = commit_a.tree.diff_to_tree(commit_b.tree) assert diff.patch == PATCH - assert len(diff) == len([patch for patch in diff]) + assert len(diff) == len(list(diff)) def test_diff_ids(barerepo): @@ -296,7 +295,7 @@ def test_hunk_content(barerepo): patch = commit_a.tree.diff_to_tree(commit_b.tree)[0] hunk = patch.hunks[0] lines = (f'{x.origin} {x.content}' for x in hunk.lines) - assert HUNK_EXPECTED == ''.join(lines) + assert ''.join(lines) == HUNK_EXPECTED for line in hunk.lines: assert line.content == line.raw_content.decode() @@ -321,13 +320,13 @@ def test_diff_stats(barerepo): diff = commit_a.tree.diff_to_tree(commit_b.tree) stats = diff.stats - assert 1 == stats.insertions - assert 2 == stats.deletions - assert 2 == stats.files_changed + assert stats.insertions == 1 + assert stats.deletions == 2 + assert stats.files_changed == 2 formatted = stats.format( format=DiffStatsFormat.FULL | DiffStatsFormat.INCLUDE_SUMMARY, width=80 ) - assert STATS_EXPECTED == formatted + assert formatted == STATS_EXPECTED def test_deltas(barerepo): @@ -357,12 +356,12 @@ def test_diff_parse(barerepo): diff = pygit2.Diff.parse_diff(PATCH) stats = diff.stats - assert 2 == stats.deletions - assert 1 == stats.insertions - assert 2 == stats.files_changed + assert stats.deletions == 2 + assert stats.insertions == 1 + assert stats.files_changed == 2 deltas = list(diff.deltas) - assert 2 == len(deltas) + assert len(deltas) == 2 def test_parse_diff_null(): diff --git a/test/test_diff_binary.py b/test/test_diff_binary.py index 17eceaac..b4b877db 100644 --- a/test/test_diff_binary.py +++ b/test/test_diff_binary.py @@ -56,10 +56,10 @@ def repo(tmp_path): def test_binary_diff(repo): diff = repo.diff('HEAD', 'HEAD^') - assert PATCH_BINARY == diff.patch + assert diff.patch == PATCH_BINARY diff = repo.diff('HEAD', 'HEAD^', flags=DiffOption.SHOW_BINARY) - assert PATCH_BINARY_SHOW == diff.patch + assert diff.patch == PATCH_BINARY_SHOW diff = repo.diff(b'HEAD', b'HEAD^') - assert PATCH_BINARY == diff.patch + assert diff.patch == PATCH_BINARY diff = repo.diff(b'HEAD', b'HEAD^', flags=DiffOption.SHOW_BINARY) - assert PATCH_BINARY_SHOW == diff.patch + assert diff.patch == PATCH_BINARY_SHOW diff --git a/test/test_filter.py b/test/test_filter.py index f37f9e1c..43ce09c7 100644 --- a/test/test_filter.py +++ b/test/test_filter.py @@ -1,5 +1,6 @@ -from io import BytesIO import codecs +from io import BytesIO + import pytest import pygit2 @@ -75,44 +76,44 @@ def test_filter(testrepo, rot13_filter): blob_oid = testrepo.create_blob_fromworkdir('bye.txt') blob = testrepo[blob_oid] flags = BlobFilter.CHECK_FOR_BINARY | BlobFilter.ATTRIBUTES_FROM_HEAD - assert b'olr jbeyq\n' == blob.data + assert blob.data == b'olr jbeyq\n' with pygit2.BlobIO(blob) as reader: - assert b'olr jbeyq\n' == reader.read() + assert reader.read() == b'olr jbeyq\n' with pygit2.BlobIO(blob, as_path='bye.txt', flags=flags) as reader: - assert b'bye world\n' == reader.read() + assert reader.read() == b'bye world\n' def test_filter_buffered(testrepo, buffered_filter): blob_oid = testrepo.create_blob_fromworkdir('bye.txt') blob = testrepo[blob_oid] flags = BlobFilter.CHECK_FOR_BINARY | BlobFilter.ATTRIBUTES_FROM_HEAD - assert b'olr jbeyq\n' == blob.data + assert blob.data == b'olr jbeyq\n' with pygit2.BlobIO(blob) as reader: - assert b'olr jbeyq\n' == reader.read() + assert reader.read() == b'olr jbeyq\n' with pygit2.BlobIO(blob, 'bye.txt', flags=flags) as reader: - assert b'bye world\n' == reader.read() + assert reader.read() == b'bye world\n' def test_filter_passthrough(testrepo, passthrough_filter): blob_oid = testrepo.create_blob_fromworkdir('bye.txt') blob = testrepo[blob_oid] flags = BlobFilter.CHECK_FOR_BINARY | BlobFilter.ATTRIBUTES_FROM_HEAD - assert b'bye world\n' == blob.data + assert blob.data == b'bye world\n' with pygit2.BlobIO(blob) as reader: - assert b'bye world\n' == reader.read() + assert reader.read() == b'bye world\n' with pygit2.BlobIO(blob, 'bye.txt', flags=flags) as reader: - assert b'bye world\n' == reader.read() + assert reader.read() == b'bye world\n' def test_filter_unmatched(testrepo, unmatched_filter): blob_oid = testrepo.create_blob_fromworkdir('bye.txt') blob = testrepo[blob_oid] flags = BlobFilter.CHECK_FOR_BINARY | BlobFilter.ATTRIBUTES_FROM_HEAD - assert b'bye world\n' == blob.data + assert blob.data == b'bye world\n' with pygit2.BlobIO(blob) as reader: - assert b'bye world\n' == reader.read() + assert reader.read() == b'bye world\n' with pygit2.BlobIO(blob, as_path='bye.txt', flags=flags) as reader: - assert b'bye world\n' == reader.read() + assert reader.read() == b'bye world\n' def test_filter_cleanup(dirtyrepo, rot13_filter): diff --git a/test/test_index.py b/test/test_index.py index cf10eefd..beaf9c0f 100644 --- a/test/test_index.py +++ b/test/test_index.py @@ -30,8 +30,9 @@ import pytest import pygit2 -from pygit2 import Repository, Index, Oid +from pygit2 import Index, Oid, Repository from pygit2.enums import FileMode + from . import utils @@ -164,7 +165,7 @@ def test_iter(testrepo): # Compare SHAs, not IndexEntry object identity entries = [index[x].id for x in range(n)] - assert list(x.id for x in index) == entries + assert [x.id for x in index] == entries def test_mode(testrepo): @@ -224,9 +225,9 @@ def test_change_attributes(testrepo): entry.path = 'foo.txt' entry.id = ign_entry.id entry.mode = FileMode.BLOB_EXECUTABLE - assert 'foo.txt' == entry.path + assert entry.path == 'foo.txt' assert ign_entry.id == entry.id - assert FileMode.BLOB_EXECUTABLE == entry.mode + assert entry.mode == FileMode.BLOB_EXECUTABLE def test_write_tree_to(testrepo, tmp_path): @@ -242,7 +243,7 @@ def test_create_entry(testrepo): hello_entry = index['hello.txt'] entry = pygit2.IndexEntry('README.md', hello_entry.id, hello_entry.mode) index.add(entry) - assert '60e769e57ae1d6a2ab75d8d253139e6260e1f912' == index.write_tree() + assert index.write_tree() == '60e769e57ae1d6a2ab75d8d253139e6260e1f912' def test_create_entry_aspath(testrepo): diff --git a/test/test_mailmap.py b/test/test_mailmap.py index 0adeaa63..96765ed2 100644 --- a/test/test_mailmap.py +++ b/test/test_mailmap.py @@ -27,7 +27,6 @@ from pygit2 import Mailmap - TEST_MAILMAP = """\ # Simple Comment line diff --git a/test/test_merge.py b/test/test_merge.py index cadc1657..cd68b1bd 100644 --- a/test/test_merge.py +++ b/test/test_merge.py @@ -30,7 +30,7 @@ import pytest import pygit2 -from pygit2.enums import FileStatus, MergeAnalysis, MergeFavor, MergeFlag, MergeFileFlag +from pygit2.enums import FileStatus, MergeAnalysis, MergeFavor, MergeFileFlag, MergeFlag @pytest.mark.parametrize('id', [None, 42]) @@ -46,12 +46,12 @@ def test_merge_analysis_uptodate(mergerepo): analysis, preference = mergerepo.merge_analysis(branch_id) assert analysis & MergeAnalysis.UP_TO_DATE assert not analysis & MergeAnalysis.FASTFORWARD - assert {} == mergerepo.status() + assert mergerepo.status() == {} analysis, preference = mergerepo.merge_analysis(branch_id, 'refs/heads/ff-branch') assert analysis & MergeAnalysis.UP_TO_DATE assert not analysis & MergeAnalysis.FASTFORWARD - assert {} == mergerepo.status() + assert mergerepo.status() == {} def test_merge_analysis_fastforward(mergerepo): @@ -61,12 +61,12 @@ def test_merge_analysis_fastforward(mergerepo): analysis, preference = mergerepo.merge_analysis(branch_id) assert not analysis & MergeAnalysis.UP_TO_DATE assert analysis & MergeAnalysis.FASTFORWARD - assert {} == mergerepo.status() + assert mergerepo.status() == {} analysis, preference = mergerepo.merge_analysis(branch_id, 'refs/heads/master') assert not analysis & MergeAnalysis.UP_TO_DATE assert analysis & MergeAnalysis.FASTFORWARD - assert {} == mergerepo.status() + assert mergerepo.status() == {} def test_merge_no_fastforward_no_conflicts(mergerepo): @@ -76,8 +76,8 @@ def test_merge_no_fastforward_no_conflicts(mergerepo): assert not analysis & MergeAnalysis.UP_TO_DATE assert not analysis & MergeAnalysis.FASTFORWARD # Asking twice to assure the reference counting is correct - assert {} == mergerepo.status() - assert {} == mergerepo.status() + assert mergerepo.status() == {} + assert mergerepo.status() == {} def test_merge_invalid_hex(mergerepo): @@ -113,22 +113,22 @@ def test_merge_no_fastforward_conflicts(mergerepo): status = FileStatus.CONFLICTED # Asking twice to assure the reference counting is correct - assert {'.gitignore': status} == mergerepo.status() - assert {'.gitignore': status} == mergerepo.status() + assert mergerepo.status() == {'.gitignore': status} + assert mergerepo.status() == {'.gitignore': status} ancestor, ours, theirs = mergerepo.index.conflicts['.gitignore'] assert ancestor is None assert ours is not None assert theirs is not None - assert '.gitignore' == ours.path - assert '.gitignore' == theirs.path - assert 1 == len(list(mergerepo.index.conflicts)) + assert ours.path == '.gitignore' + assert theirs.path == '.gitignore' + assert len(list(mergerepo.index.conflicts)) == 1 # Checking the index works as expected mergerepo.index.add('.gitignore') mergerepo.index.write() assert mergerepo.index.conflicts is None - assert {'.gitignore': FileStatus.INDEX_MODIFIED} == mergerepo.status() + assert mergerepo.status() == {'.gitignore': FileStatus.INDEX_MODIFIED} def test_merge_remove_conflicts(mergerepo): diff --git a/test/test_note.py b/test/test_note.py index dbd85ec9..7a761d95 100644 --- a/test/test_note.py +++ b/test/test_note.py @@ -25,9 +25,9 @@ """Tests for note objects.""" -from pygit2 import Signature import pytest +from pygit2 import Signature NOTE = ('6c8980ba963cad8b25a9bcaf68d4023ee57370d8', 'note message') diff --git a/test/test_object.py b/test/test_object.py index 40c01d7a..c42dd873 100644 --- a/test/test_object.py +++ b/test/test_object.py @@ -27,10 +27,9 @@ import pytest -from pygit2 import Tree, Tag +from pygit2 import Tag, Tree from pygit2.enums import ObjectType - BLOB_SHA = 'a520c24d85fbfc815d385957eed41406ca5a860b' BLOB_CONTENT = """hello world hola mundo @@ -48,7 +47,7 @@ def test_equality(testrepo): assert commit_a is not commit_b assert commit_a == commit_b - assert not (commit_a != commit_b) + assert commit_a == commit_b def test_hashing(testrepo): diff --git a/test/test_odb.py b/test/test_odb.py index fe91c957..8724248d 100644 --- a/test/test_odb.py +++ b/test/test_odb.py @@ -34,8 +34,8 @@ # pygit2 from pygit2 import Odb, Oid from pygit2.enums import ObjectType -from . import utils +from . import utils BLOB_HEX = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16' BLOB_RAW = binascii.unhexlify(BLOB_HEX.encode('ascii')) @@ -74,14 +74,14 @@ def test_read(odb): ab = odb.read(BLOB_OID) a = odb.read(BLOB_HEX) assert ab == a - assert (ObjectType.BLOB, b'a contents\n') == a + assert a == (ObjectType.BLOB, b'a contents\n') a2 = odb.read('7f129fd57e31e935c6d60a0c794efe4e6927664b') - assert (ObjectType.BLOB, b'a contents 2\n') == a2 + assert a2 == (ObjectType.BLOB, b'a contents 2\n') a_hex_prefix = BLOB_HEX[:4] a3 = odb.read(a_hex_prefix) - assert (ObjectType.BLOB, b'a contents\n') == a3 + assert a3 == (ObjectType.BLOB, b'a contents\n') def test_write(odb): diff --git a/test/test_odb_backend.py b/test/test_odb_backend.py index c99d47f4..f91d6f04 100644 --- a/test/test_odb_backend.py +++ b/test/test_odb_backend.py @@ -34,8 +34,8 @@ # pygit2 import pygit2 from pygit2.enums import ObjectType -from . import utils +from . import utils BLOB_HEX = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16' BLOB_RAW = binascii.unhexlify(BLOB_HEX.encode('ascii')) @@ -106,7 +106,7 @@ def proxy(barerepo): def test_iterable(proxy): - assert BLOB_HEX in [o for o in proxy] + assert BLOB_HEX in list(proxy) def test_read(proxy): @@ -117,13 +117,13 @@ def test_read(proxy): ab = proxy.read(BLOB_OID) a = proxy.read(BLOB_HEX) assert ab == a - assert (ObjectType.BLOB, b'a contents\n') == a + assert a == (ObjectType.BLOB, b'a contents\n') def test_read_prefix(proxy): a_hex_prefix = BLOB_HEX[:4] a3 = proxy.read_prefix(a_hex_prefix) - assert (ObjectType.BLOB, b'a contents\n', BLOB_OID) == a3 + assert a3 == (ObjectType.BLOB, b'a contents\n', BLOB_OID) def test_exists(proxy): @@ -136,7 +136,7 @@ def test_exists(proxy): def test_exists_prefix(proxy): a_hex_prefix = BLOB_HEX[:4] - assert BLOB_HEX == proxy.exists_prefix(a_hex_prefix) + assert proxy.exists_prefix(a_hex_prefix) == BLOB_HEX # diff --git a/test/test_oid.py b/test/test_oid.py index c16d688f..e2070ec7 100644 --- a/test/test_oid.py +++ b/test/test_oid.py @@ -28,9 +28,9 @@ # Standard Library from binascii import unhexlify -from pygit2 import Oid import pytest +from pygit2 import Oid HEX = '15b648aec6ed045b5ca6f57f8b7831a8b4757298' RAW = unhexlify(HEX.encode('ascii')) @@ -85,7 +85,7 @@ def test_cmp(): # Other assert oid1 < oid2 assert oid1 <= oid2 - assert not oid1 == oid2 + assert oid1 != oid2 assert not oid1 > oid2 assert not oid1 >= oid2 diff --git a/test/test_packbuilder.py b/test/test_packbuilder.py index f61d475f..235b79b8 100644 --- a/test/test_packbuilder.py +++ b/test/test_packbuilder.py @@ -29,6 +29,7 @@ import pygit2 from pygit2 import PackBuilder + from . import utils @@ -41,7 +42,7 @@ def test_create_packbuilder(testrepo): def test_add(testrepo): # Add a few objects and confirm that the count is correct packbuilder = PackBuilder(testrepo) - objects_to_add = [obj for obj in testrepo] + objects_to_add = list(testrepo) packbuilder.add(objects_to_add[0]) assert len(packbuilder) == 1 packbuilder.add(objects_to_add[1]) @@ -98,14 +99,14 @@ def confirm_same_repo_after_packing(testrepo, tmp_path, pack_delegate): # assert that the number of written objects is the same as the number of objects in the repo written_objects = testrepo.pack(pack_path, pack_delegate=pack_delegate) - assert written_objects == len([obj for obj in testrepo]) + assert written_objects == len(list(testrepo)) # assert that the number of objects in the pack repo is the same as the original repo - orig_objects = [obj for obj in testrepo.odb] - packed_objects = [obj for obj in pack_repo.odb] + orig_objects = list(testrepo.odb) + packed_objects = list(pack_repo.odb) assert len(packed_objects) == len(orig_objects) # assert that the objects in the packed repo are the same objects as the original repo - for i, obj in enumerate(orig_objects): + for _i, obj in enumerate(orig_objects): assert pack_repo[obj].type == testrepo[obj].type assert pack_repo[obj].read_raw() == testrepo[obj].read_raw() diff --git a/test/test_patch.py b/test/test_patch.py index d15a2e53..6c4496ae 100644 --- a/test/test_patch.py +++ b/test/test_patch.py @@ -23,9 +23,9 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. -import pygit2 import pytest +import pygit2 BLOB_OLD_SHA = 'a520c24d85fbfc815d385957eed41406ca5a860b' BLOB_NEW_SHA = '3b18e512dba79e4c8300dd08aeb37f8e728b8dad' diff --git a/test/test_patch_encoding.py b/test/test_patch_encoding.py index 12f8b514..bd2b2a8d 100644 --- a/test/test_patch_encoding.py +++ b/test/test_patch_encoding.py @@ -25,7 +25,6 @@ import pygit2 - expected_diff = b"""diff --git a/iso-8859-1.txt b/iso-8859-1.txt index e84e339..201e0c9 100644 --- a/iso-8859-1.txt diff --git a/test/test_refdb_backend.py b/test/test_refdb_backend.py index 19a944b1..c4913e91 100644 --- a/test/test_refdb_backend.py +++ b/test/test_refdb_backend.py @@ -27,9 +27,10 @@ from pathlib import Path -import pygit2 import pytest +import pygit2 + # Note: the refdb abstraction from libgit2 is meant to provide information # which libgit2 transforms into something more useful, and in general YMMV by diff --git a/test/test_refs.py b/test/test_refs.py index a6caa103..3f8aaf1e 100644 --- a/test/test_refs.py +++ b/test/test_refs.py @@ -29,11 +29,17 @@ import pytest -from pygit2 import Commit, Signature, Tree, reference_is_valid_name -from pygit2 import AlreadyExistsError, GitError, InvalidSpecError +from pygit2 import ( + AlreadyExistsError, + Commit, + GitError, + InvalidSpecError, + Signature, + Tree, + reference_is_valid_name, +) from pygit2.enums import ReferenceType - LAST_COMMIT = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98' @@ -60,8 +66,8 @@ def test_refs_list(testrepo): def test_head(testrepo): head = testrepo.head - assert LAST_COMMIT == testrepo[head.target].id - assert LAST_COMMIT == testrepo[head.raw_target].id + assert testrepo[head.target].id == LAST_COMMIT + assert testrepo[head.raw_target].id == LAST_COMMIT def test_refs_getitem(testrepo): @@ -150,11 +156,11 @@ def test_refs_delete(testrepo): # Access the deleted reference with pytest.raises(GitError): - getattr(reference, 'name') + reference.name with pytest.raises(GitError): - getattr(reference, 'type') + reference.type with pytest.raises(GitError): - getattr(reference, 'target') + reference.target with pytest.raises(GitError): reference.delete() with pytest.raises(GitError): @@ -261,10 +267,10 @@ def test_refs_equality(testrepo): assert ref1 is not ref2 assert ref1 == ref2 - assert not ref1 != ref2 + assert ref1 == ref2 assert ref1 != ref3 - assert not ref1 == ref3 + assert ref1 != ref3 def test_refs_compress(testrepo): @@ -583,11 +589,11 @@ def test_delete(testrepo): # Access the deleted reference with pytest.raises(GitError): - getattr(reference, 'name') + reference.name with pytest.raises(GitError): - getattr(reference, 'type') + reference.type with pytest.raises(GitError): - getattr(reference, 'target') + reference.target with pytest.raises(GitError): reference.delete() with pytest.raises(GitError): diff --git a/test/test_remote.py b/test/test_remote.py index 0688cbb0..6f5fc578 100644 --- a/test/test_remote.py +++ b/test/test_remote.py @@ -25,16 +25,16 @@ """Tests for Remote objects.""" -from unittest.mock import patch import sys +from unittest.mock import patch import pytest import pygit2 from pygit2 import Oid from pygit2.ffi import ffi -from . import utils +from . import utils REMOTE_NAME = 'origin' REMOTE_URL = 'https://github.com/libgit2/pygit2.git' @@ -84,8 +84,8 @@ def test_remote_create_anonymous(testrepo): assert remote.name is None assert url == remote.url assert remote.push_url is None - assert [] == remote.fetch_refspecs - assert [] == remote.push_refspecs + assert remote.fetch_refspecs == [] + assert remote.push_refspecs == [] def test_remote_delete(testrepo): @@ -93,21 +93,21 @@ def test_remote_delete(testrepo): url = 'https://github.com/libgit2/pygit2.git' testrepo.remotes.create(name, url) - assert 2 == len(testrepo.remotes) + assert len(testrepo.remotes) == 2 remote = testrepo.remotes[1] assert name == remote.name testrepo.remotes.delete(remote.name) - assert 1 == len(testrepo.remotes) + assert len(testrepo.remotes) == 1 def test_remote_rename(testrepo): remote = testrepo.remotes[0] - assert REMOTE_NAME == remote.name + assert remote.name == REMOTE_NAME problems = testrepo.remotes.rename(remote.name, 'new') - assert [] == problems - assert 'new' != remote.name + assert problems == [] + assert remote.name != 'new' with pytest.raises(ValueError): testrepo.remotes.rename('', '') @@ -117,7 +117,7 @@ def test_remote_rename(testrepo): def test_remote_set_url(testrepo): remote = testrepo.remotes['origin'] - assert REMOTE_URL == remote.url + assert remote.url == REMOTE_URL new_url = 'https://github.com/cholin/pygit2.git' testrepo.remotes.set_url('origin', new_url) @@ -142,34 +142,34 @@ def test_refspec(testrepo): assert refspec.src == REMOTE_FETCHSPEC_SRC assert refspec.dst == REMOTE_FETCHSPEC_DST assert refspec.force is True - assert ORIGIN_REFSPEC == refspec.string + assert refspec.string == ORIGIN_REFSPEC assert list == type(remote.fetch_refspecs) - assert 1 == len(remote.fetch_refspecs) - assert ORIGIN_REFSPEC == remote.fetch_refspecs[0] + assert len(remote.fetch_refspecs) == 1 + assert remote.fetch_refspecs[0] == ORIGIN_REFSPEC assert refspec.src_matches('refs/heads/master') assert refspec.dst_matches('refs/remotes/origin/master') - assert 'refs/remotes/origin/master' == refspec.transform('refs/heads/master') - assert 'refs/heads/master' == refspec.rtransform('refs/remotes/origin/master') + assert refspec.transform('refs/heads/master') == 'refs/remotes/origin/master' + assert refspec.rtransform('refs/remotes/origin/master') == 'refs/heads/master' assert list == type(remote.push_refspecs) - assert 0 == len(remote.push_refspecs) + assert len(remote.push_refspecs) == 0 push_specs = remote.push_refspecs assert list == type(push_specs) - assert 0 == len(push_specs) + assert len(push_specs) == 0 testrepo.remotes.add_fetch('origin', '+refs/test/*:refs/test/remotes/*') remote = testrepo.remotes['origin'] fetch_specs = remote.fetch_refspecs assert list == type(fetch_specs) - assert 2 == len(fetch_specs) - assert [ + assert len(fetch_specs) == 2 + assert fetch_specs == [ '+refs/heads/*:refs/remotes/origin/*', '+refs/test/*:refs/test/remotes/*', - ] == fetch_specs + ] testrepo.remotes.add_push('origin', '+refs/test/*:refs/test/remotes/*') @@ -177,14 +177,14 @@ def test_refspec(testrepo): testrepo.remotes.add_fetch(['+refs/*:refs/*', 5]) remote = testrepo.remotes['origin'] - assert ['+refs/test/*:refs/test/remotes/*'] == remote.push_refspecs + assert remote.push_refspecs == ['+refs/test/*:refs/test/remotes/*'] def test_remote_list(testrepo): - assert 1 == len(testrepo.remotes) + assert len(testrepo.remotes) == 1 remote = testrepo.remotes[0] - assert REMOTE_NAME == remote.name - assert REMOTE_URL == remote.url + assert remote.name == REMOTE_NAME + assert remote.url == REMOTE_URL name = 'upstream' url = 'https://github.com/libgit2/pygit2.git' @@ -195,7 +195,7 @@ def test_remote_list(testrepo): @utils.requires_network def test_ls_remotes(testrepo): - assert 1 == len(testrepo.remotes) + assert len(testrepo.remotes) == 1 remote = testrepo.remotes[0] refs = remote.ls_remotes() @@ -207,8 +207,8 @@ def test_ls_remotes(testrepo): def test_remote_collection(testrepo): remote = testrepo.remotes['origin'] - assert REMOTE_NAME == remote.name - assert REMOTE_URL == remote.url + assert remote.name == REMOTE_NAME + assert remote.url == REMOTE_URL with pytest.raises(KeyError): testrepo.remotes['upstream'] diff --git a/test/test_remote_utf8.py b/test/test_remote_utf8.py index bd410218..5e4b5372 100644 --- a/test/test_remote_utf8.py +++ b/test/test_remote_utf8.py @@ -23,8 +23,10 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. -import pygit2 import pytest + +import pygit2 + from . import utils diff --git a/test/test_repository.py b/test/test_repository.py index fb240323..4fa76861 100644 --- a/test/test_repository.py +++ b/test/test_repository.py @@ -23,16 +23,15 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. -from pathlib import Path import shutil import tempfile +from pathlib import Path import pytest # pygit2 import pygit2 -from pygit2 import init_repository, clone_repository, discover_repository -from pygit2 import Oid +from pygit2 import Oid, clone_repository, discover_repository, init_repository from pygit2.enums import ( CheckoutNotify, CheckoutStrategy, @@ -43,6 +42,7 @@ ResetMode, StashApplyProgress, ) + from . import utils @@ -151,7 +151,7 @@ def checkout_notify(self, why, path, baseline, target, workdir): head = testrepo.head head = testrepo[head.target] assert 'new' not in head.tree - assert b'bye world\n' == read_bye_txt() + assert read_bye_txt() == b'bye world\n' callbacks = MyCheckoutCallbacks() # checkout i18n with GIT_CHECKOUT_FORCE - callbacks should prevent checkout from completing @@ -162,7 +162,7 @@ def checkout_notify(self, why, path, baseline, target, workdir): assert callbacks.invoked_times == 2 assert 'new' not in head.tree - assert b'bye world\n' == read_bye_txt() + assert read_bye_txt() == b'bye world\n' def test_checkout_branch(testrepo): @@ -219,7 +219,7 @@ def test_checkout_alternative_dir(testrepo): extra_dir.mkdir() assert len(list(extra_dir.iterdir())) == 0 testrepo.checkout(ref_i18n, directory=extra_dir) - assert not len(list(extra_dir.iterdir())) == 0 + assert len(list(extra_dir.iterdir())) != 0 def test_checkout_paths(testrepo): @@ -277,15 +277,15 @@ def test_ahead_behind(testrepo): '5ebeeebb320790caf276b9fc8b24546d63316533', '4ec4389a8068641da2d6578db0419484972284c8', ) - assert 1 == ahead - assert 2 == behind + assert ahead == 1 + assert behind == 2 ahead, behind = testrepo.ahead_behind( '4ec4389a8068641da2d6578db0419484972284c8', '5ebeeebb320790caf276b9fc8b24546d63316533', ) - assert 2 == ahead - assert 1 == behind + assert ahead == 2 + assert behind == 1 def test_reset_hard(testrepo): @@ -360,7 +360,7 @@ def test_stash(testrepo): ) # make sure we're starting with no stashes - assert [] == testrepo.listall_stashes() + assert testrepo.listall_stashes() == [] # some changes to working dir with (Path(testrepo.workdir) / 'hello.txt').open('w') as f: @@ -370,7 +370,7 @@ def test_stash(testrepo): assert 'hello.txt' not in testrepo.status() repo_stashes = testrepo.listall_stashes() - assert 1 == len(repo_stashes) + assert len(repo_stashes) == 1 assert repr(repo_stashes[0]) == f'' assert repo_stashes[0].commit_id == stash_hash assert repo_stashes[0].message == 'On master: ' + stash_message @@ -380,7 +380,7 @@ def test_stash(testrepo): assert repo_stashes == testrepo.listall_stashes() # still the same stashes testrepo.stash_drop() - assert [] == testrepo.listall_stashes() + assert testrepo.listall_stashes() == [] with pytest.raises(KeyError): testrepo.stash_pop() @@ -393,7 +393,7 @@ def test_stash_partial(testrepo): ) # make sure we're starting with no stashes - assert [] == testrepo.listall_stashes() + assert testrepo.listall_stashes() == [] # some changes to working dir with (Path(testrepo.workdir) / 'hello.txt').open('w') as f: @@ -411,7 +411,7 @@ def stash_pathspecs(paths): ) stash_commit = testrepo[stash_id].peel(pygit2.Commit) stash_diff = testrepo.diff(stash_commit.parents[0], stash_commit) - stash_files = set(patch.delta.new_file.path for patch in stash_diff) + stash_files = {patch.delta.new_file.path for patch in stash_diff} return stash_files == set(paths) # Stash a modified file @@ -492,7 +492,7 @@ def stash_apply_progress(self, progress: StashApplyProgress): # and since we didn't let stash_pop run to completion, the stash itself should still be here repo_stashes = testrepo.listall_stashes() - assert 1 == len(repo_stashes) + assert len(repo_stashes) == 1 assert repo_stashes[0].message == 'On master: custom stash message' @@ -579,8 +579,8 @@ def test_default_signature(testrepo): config['user.email'] = 'rjh@example.com' sig = testrepo.default_signature - assert 'Random J Hacker' == sig.name - assert 'rjh@example.com' == sig.email + assert sig.name == 'Random J Hacker' + assert sig.email == 'rjh@example.com' def test_new_repo(tmp_path): diff --git a/test/test_repository_bare.py b/test/test_repository_bare.py index d418acdf..00fb6c45 100644 --- a/test/test_repository_bare.py +++ b/test/test_repository_bare.py @@ -26,15 +26,16 @@ # Standard Library import binascii import os -from pathlib import Path import sys import tempfile +from pathlib import Path + import pytest import pygit2 from pygit2.enums import FileMode, ObjectType -from . import utils +from . import utils HEAD_SHA = '784855caf26449a1914d2cf62d12b9374d76ae78' PARENT_SHA = 'f5e5aa4e36ab0fe62ee1ccc6eb8f79b866863b87' # HEAD^ @@ -53,7 +54,7 @@ def test_is_bare(barerepo): def test_head(barerepo): head = barerepo.head - assert HEAD_SHA == head.target + assert head.target == HEAD_SHA assert type(head) == pygit2.Reference assert not barerepo.head_is_unborn assert not barerepo.head_is_detached @@ -77,14 +78,14 @@ def test_read(barerepo): ab = barerepo.read(BLOB_OID) a = barerepo.read(BLOB_HEX) assert ab == a - assert (ObjectType.BLOB, b'a contents\n') == a + assert a == (ObjectType.BLOB, b'a contents\n') a2 = barerepo.read('7f129fd57e31e935c6d60a0c794efe4e6927664b') - assert (ObjectType.BLOB, b'a contents 2\n') == a2 + assert a2 == (ObjectType.BLOB, b'a contents 2\n') a_hex_prefix = BLOB_HEX[:4] a3 = barerepo.read(a_hex_prefix) - assert (ObjectType.BLOB, b'a contents\n') == a3 + assert a3 == (ObjectType.BLOB, b'a contents\n') def test_write(barerepo): @@ -109,7 +110,7 @@ def test_contains(barerepo): def test_iterable(barerepo): oid = pygit2.Oid(hex=BLOB_HEX) - assert oid in [obj for obj in barerepo] + assert oid in list(barerepo) def test_lookup_blob(barerepo): @@ -117,23 +118,23 @@ def test_lookup_blob(barerepo): barerepo[123] assert barerepo[BLOB_OID].id == BLOB_HEX a = barerepo[BLOB_HEX] - assert b'a contents\n' == a.read_raw() - assert BLOB_HEX == a.id - assert ObjectType.BLOB == a.type + assert a.read_raw() == b'a contents\n' + assert a.id == BLOB_HEX + assert a.type == ObjectType.BLOB def test_lookup_blob_prefix(barerepo): a = barerepo[BLOB_HEX[:5]] - assert b'a contents\n' == a.read_raw() - assert BLOB_HEX == a.id - assert ObjectType.BLOB == a.type + assert a.read_raw() == b'a contents\n' + assert a.id == BLOB_HEX + assert a.type == ObjectType.BLOB def test_lookup_commit(barerepo): commit_sha = '5fe808e8953c12735680c257f56600cb0de44b10' commit = barerepo[commit_sha] assert commit_sha == commit.id - assert ObjectType.COMMIT == commit.type + assert commit.type == ObjectType.COMMIT assert commit.message == ( 'Second test data commit.\n\n' 'This commit has some additional text.\n' ) @@ -145,10 +146,10 @@ def test_lookup_commit_prefix(barerepo): too_short_prefix = commit_sha[:3] commit = barerepo[commit_sha_prefix] assert commit_sha == commit.id - assert ObjectType.COMMIT == commit.type + assert commit.type == ObjectType.COMMIT assert ( - 'Second test data commit.\n\n' - 'This commit has some additional text.\n' == commit.message + commit.message == 'Second test data commit.\n\n' + 'This commit has some additional text.\n' ) with pytest.raises(ValueError): barerepo.__getitem__(too_short_prefix) diff --git a/test/test_repository_custom.py b/test/test_repository_custom.py index 5961ef65..a1acba78 100644 --- a/test/test_repository_custom.py +++ b/test/test_repository_custom.py @@ -24,6 +24,7 @@ # Boston, MA 02110-1301, USA. from pathlib import Path + import pytest import pygit2 @@ -58,4 +59,4 @@ def test_references(repo): def test_objects(repo): a = repo.read('323fae03f4606ea9991df8befbb2fca795e648fa') - assert (ObjectType.BLOB, b'foobar\n') == a + assert a == (ObjectType.BLOB, b'foobar\n') diff --git a/test/test_revparse.py b/test/test_revparse.py index 0bc7b40f..bc076c23 100644 --- a/test/test_revparse.py +++ b/test/test_revparse.py @@ -25,9 +25,10 @@ """Tests for revision parsing.""" +from pytest import raises + from pygit2 import InvalidSpecError from pygit2.enums import RevSpecFlag -from pytest import raises HEAD_SHA = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98' PARENT_SHA = '5ebeeebb320790caf276b9fc8b24546d63316533' # HEAD^ diff --git a/test/test_revwalk.py b/test/test_revwalk.py index a4edd7c8..faa80b37 100644 --- a/test/test_revwalk.py +++ b/test/test_revwalk.py @@ -27,7 +27,6 @@ from pygit2.enums import SortMode - # In the order given by git log log = [ '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98', @@ -108,8 +107,8 @@ def test_simplify_first_parent(testrepo): def test_default_sorting(testrepo): walker = testrepo.walk(log[0], SortMode.NONE) - list1 = list([x.id for x in walker]) + list1 = [x.id for x in walker] walker = testrepo.walk(log[0]) - list2 = list([x.id for x in walker]) + list2 = [x.id for x in walker] assert list1 == list2 diff --git a/test/test_signature.py b/test/test_signature.py index fbbc99c6..e4466a83 100644 --- a/test/test_signature.py +++ b/test/test_signature.py @@ -99,7 +99,7 @@ def test_incorrect_encoding(): ) # repr() and str() may display junk, but they must not crash - assert "pygit2.Signature('(error)', '(error)', 999, 0, '(error)')" == repr( - signature + assert ( + repr(signature) == "pygit2.Signature('(error)', '(error)', 999, 0, '(error)')" ) - assert '(error) <(error)>' == str(signature) + assert str(signature) == '(error) <(error)>' diff --git a/test/test_submodule.py b/test/test_submodule.py index bf456e97..a91ab5a0 100644 --- a/test/test_submodule.py +++ b/test/test_submodule.py @@ -27,12 +27,13 @@ from pathlib import Path -import pygit2 import pytest -from . import utils -from pygit2.enums import SubmoduleIgnore as SI, SubmoduleStatus as SS +import pygit2 +from pygit2.enums import SubmoduleIgnore as SI +from pygit2.enums import SubmoduleStatus as SS +from . import utils SUBM_NAME = 'TestGitRepository' SUBM_PATH = 'TestGitRepository' @@ -108,17 +109,17 @@ class CustomRepoClass(pygit2.Repository): def test_name(repo): s = repo.submodules[SUBM_PATH] - assert SUBM_NAME == s.name + assert s.name == SUBM_NAME def test_path(repo): s = repo.submodules[SUBM_PATH] - assert SUBM_PATH == s.path + assert s.path == SUBM_PATH def test_url(repo): s = repo.submodules[SUBM_PATH] - assert SUBM_URL == s.url + assert s.url == SUBM_URL def test_missing_url(repo): @@ -239,7 +240,7 @@ def test_add_submodule(repo, depth): sm_repo = sm.open() assert sm_repo_path == sm.path - assert SUBM_URL == sm.url + assert sm.url == SUBM_URL assert not sm_repo.is_empty if depth == 0: diff --git a/test/test_tag.py b/test/test_tag.py index 73cfcf0b..d31b9dc3 100644 --- a/test/test_tag.py +++ b/test/test_tag.py @@ -30,7 +30,6 @@ import pygit2 from pygit2.enums import ObjectType - TAG_SHA = '3d2962987c695a29f1f80b6c3aa4ec046ef44369' @@ -39,11 +38,11 @@ def test_read_tag(barerepo): tag = repo[TAG_SHA] target = repo[tag.target] assert isinstance(tag, pygit2.Tag) - assert ObjectType.TAG == tag.type - assert ObjectType.COMMIT == target.type - assert 'root' == tag.name - assert 'Tagged root commit.\n' == tag.message - assert 'Initial test data commit.\n' == target.message + assert tag.type == ObjectType.TAG + assert target.type == ObjectType.COMMIT + assert tag.name == 'root' + assert tag.message == 'Tagged root commit.\n' + assert target.message == 'Initial test data commit.\n' assert tag.tagger == pygit2.Signature( 'Dave Borowitz', 'dborowitz@google.com', 1288724692, -420 ) @@ -63,7 +62,7 @@ def test_new_tag(barerepo): sha = barerepo.create_tag(name, target_prefix, ObjectType.BLOB, tagger, message) tag = barerepo[sha] - assert '3ee44658fd11660e828dfc96b9b5c5f38d5b49bb' == tag.id + assert tag.id == '3ee44658fd11660e828dfc96b9b5c5f38d5b49bb' assert name == tag.name assert target == tag.target assert tagger == tag.tagger diff --git a/test/test_tree.py b/test/test_tree.py index 0f9ec2d1..01c474c7 100644 --- a/test/test_tree.py +++ b/test/test_tree.py @@ -24,6 +24,7 @@ # Boston, MA 02110-1301, USA. import operator + import pytest import pygit2 @@ -31,7 +32,6 @@ from . import utils - TREE_SHA = '967fce8df97cc71722d3c2a5930ef3e6f1d27b12' SUBTREE_SHA = '614fd9a3094bf618ea938fffc00e7d1a54f89ad0' @@ -54,7 +54,7 @@ def test_read_tree(barerepo): utils.assertRaisesWithArg(IndexError, 3, lambda: tree[3]) utils.assertRaisesWithArg(KeyError, 'abcd', lambda: tree / 'abcd') - assert 3 == len(tree) + assert len(tree) == 3 sha = '7f129fd57e31e935c6d60a0c794efe4e6927664b' assert 'a' in tree assertTreeEntryEqual(tree[0], sha, 'a', 0o0100644) @@ -93,7 +93,7 @@ def test_equality(barerepo): def test_sorting(barerepo): tree_a = barerepo['18e2d2e9db075f9eb43bcb2daa65a2867d29a15e'] - assert list(tree_a) == sorted(reversed(list(tree_a)), key=pygit2.tree_entry_key) + assert list(tree_a) == sorted(tree_a, key=pygit2.tree_entry_key) assert list(tree_a) != reversed(list(tree_a)) @@ -111,7 +111,7 @@ def test_read_subtree(barerepo): assert subtree_entry.type_str == 'tree' subtree = barerepo[subtree_entry.id] - assert 1 == len(subtree) + assert len(subtree) == 1 sha = '297efb891a47de80be0cfe9c639e4b8c9b450989' assertTreeEntryEqual(subtree[0], sha, 'd', 0o0100644) @@ -185,7 +185,7 @@ def test_iterate_tree_nested(barerepo): tree = barerepo[TREE_SHA] for tree_entry in tree: if isinstance(tree_entry, pygit2.Tree): - for tree_entry2 in tree_entry: + for _tree_entry2 in tree_entry: pass diff --git a/test/utils.py b/test/utils.py index 1df9135f..952c775b 100644 --- a/test/utils.py +++ b/test/utils.py @@ -25,12 +25,12 @@ # Standard library import hashlib -from pathlib import Path import shutil import socket import stat import sys import zipfile +from pathlib import Path # Requirements import pytest @@ -38,7 +38,6 @@ # Pygit2 import pygit2 - requires_future_libgit2 = pytest.mark.skipif( pygit2.LIBGIT2_VER < (2, 0, 0), reason='This test may work with a future version of libgit2', From 6330d4b759709d15af1f693888f792838bb79339 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 19:52:51 +0700 Subject: [PATCH 04/40] add type checking configuration (use pyright) --- pyproject.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 50c037af..4f505542 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,3 +49,7 @@ lint.ignore = [ [tool.ruff.format] quote-style = "single" + +[tool.pyright] +typeCheckingMode = "strict" +pythonVersion = "3.10" From 325891bd19ad03abb961e44d99a88521747aae7e Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 20:06:57 +0700 Subject: [PATCH 05/40] add _libgit2.pyi --- pygit2/_libgit2.pyi | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 pygit2/_libgit2.pyi diff --git a/pygit2/_libgit2.pyi b/pygit2/_libgit2.pyi new file mode 100644 index 00000000..2fb45d89 --- /dev/null +++ b/pygit2/_libgit2.pyi @@ -0,0 +1,4 @@ +import _cffi_backend + +ffi: _cffi_backend.FFI +C: _cffi_backend.Lib From aa37e2d1270fe97e0441a914a14900d56e17d8c3 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 22:28:32 +0700 Subject: [PATCH 06/40] mega fix _pygit2.pyi - remove GIT_OBJ_* - add additional constants for type checking --- pygit2/_pygit2.pyi | 394 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 317 insertions(+), 77 deletions(-) diff --git a/pygit2/_pygit2.pyi b/pygit2/_pygit2.pyi index 5c3c879c..48bdabe2 100644 --- a/pygit2/_pygit2.pyi +++ b/pygit2/_pygit2.pyi @@ -1,5 +1,5 @@ from io import IOBase -from typing import Iterator, Literal, Optional, overload +from typing import Any, Iterator, Literal, Optional, TypeAlias, overload from . import Index from .enums import ( @@ -21,48 +21,284 @@ from .enums import ( SortMode, ) -GIT_OBJ_BLOB: Literal[3] -GIT_OBJ_COMMIT: Literal[1] -GIT_OBJ_TAG: Literal[4] -GIT_OBJ_TREE: Literal[2] -GIT_OID_HEXSZ: int -GIT_OID_HEX_ZERO: str -GIT_OID_MINPREFIXLEN: int -GIT_OID_RAWSZ: int +# version constants LIBGIT2_VERSION: str LIBGIT2_VER_MAJOR: int LIBGIT2_VER_MINOR: int LIBGIT2_VER_REVISION: int +# libgit2 constants +GIT_OBJECT_BLOB: Literal[3] +GIT_OBJECT_COMMIT: Literal[1] +GIT_OBJECT_TAG: Literal[4] +GIT_OBJECT_TREE: Literal[2] +GIT_OID_HEXSZ: Literal[40] +GIT_OID_HEX_ZERO: Literal['0000000000000000000000000000000000000000'] +GIT_OID_MINPREFIXLEN: Literal[4] +GIT_OID_RAWSZ: Literal[20] +GIT_APPLY_LOCATION_BOTH: Literal[2] +GIT_APPLY_LOCATION_INDEX: Literal[1] +GIT_APPLY_LOCATION_WORKDIR: Literal[0] +GIT_BLAME_FIRST_PARENT: Literal[16] +GIT_BLAME_IGNORE_WHITESPACE: Literal[64] +GIT_BLAME_NORMAL: Literal[0] +GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES: Literal[8] +GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES: Literal[4] +GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES: Literal[2] +GIT_BLAME_TRACK_COPIES_SAME_FILE: Literal[1] +GIT_BLAME_USE_MAILMAP: Literal[32] +GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT: Literal[8] +GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD: Literal[4] +GIT_BLOB_FILTER_CHECK_FOR_BINARY: Literal[1] +GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES: Literal[2] +GIT_BRANCH_ALL: Literal[3] +GIT_BRANCH_LOCAL: Literal[1] +GIT_BRANCH_REMOTE: Literal[2] +GIT_CHECKOUT_ALLOW_CONFLICTS: Literal[16] +GIT_CHECKOUT_CONFLICT_STYLE_DIFF3: Literal[2097152] +GIT_CHECKOUT_CONFLICT_STYLE_MERGE: Literal[1048576] +GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3: Literal[33554432] +GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH: Literal[8192] +GIT_CHECKOUT_DONT_OVERWRITE_IGNORED: Literal[524288] +GIT_CHECKOUT_DONT_REMOVE_EXISTING: Literal[4194304] +GIT_CHECKOUT_DONT_UPDATE_INDEX: Literal[256] +GIT_CHECKOUT_DONT_WRITE_INDEX: Literal[8388608] +GIT_CHECKOUT_DRY_RUN: Literal[16777216] +GIT_CHECKOUT_FORCE: Literal[2] +GIT_CHECKOUT_NONE: Literal[0] +GIT_CHECKOUT_NO_REFRESH: Literal[512] +GIT_CHECKOUT_RECREATE_MISSING: Literal[4] +GIT_CHECKOUT_REMOVE_IGNORED: Literal[64] +GIT_CHECKOUT_REMOVE_UNTRACKED: Literal[32] +GIT_CHECKOUT_SAFE: Literal[1] +GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES: Literal[262144] +GIT_CHECKOUT_SKIP_UNMERGED: Literal[1024] +GIT_CHECKOUT_UPDATE_ONLY: Literal[128] +GIT_CHECKOUT_USE_OURS: Literal[2048] +GIT_CHECKOUT_USE_THEIRS: Literal[4096] +GIT_CONFIG_HIGHEST_LEVEL: Literal[-1] +GIT_CONFIG_LEVEL_APP: Literal[7] +GIT_CONFIG_LEVEL_GLOBAL: Literal[4] +GIT_CONFIG_LEVEL_LOCAL: Literal[5] +GIT_CONFIG_LEVEL_PROGRAMDATA: Literal[1] +GIT_CONFIG_LEVEL_SYSTEM: Literal[2] +GIT_CONFIG_LEVEL_WORKTREE: Literal[6] +GIT_CONFIG_LEVEL_XDG: Literal[3] +GIT_DELTA_ADDED: Literal[1] +GIT_DELTA_CONFLICTED: Literal[10] +GIT_DELTA_COPIED: Literal[5] +GIT_DELTA_DELETED: Literal[2] +GIT_DELTA_IGNORED: Literal[6] +GIT_DELTA_MODIFIED: Literal[3] +GIT_DELTA_RENAMED: Literal[4] +GIT_DELTA_TYPECHANGE: Literal[8] +GIT_DELTA_UNMODIFIED: Literal[0] +GIT_DELTA_UNREADABLE: Literal[9] +GIT_DELTA_UNTRACKED: Literal[7] +GIT_DESCRIBE_ALL: Literal[2] +GIT_DESCRIBE_DEFAULT: Literal[0] +GIT_DESCRIBE_TAGS: Literal[1] +GIT_DIFF_BREAK_REWRITES: Literal[32] +GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY: Literal[32768] +GIT_DIFF_DISABLE_PATHSPEC_MATCH: Literal[4096] +GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS: Literal[16384] +GIT_DIFF_FIND_ALL: Literal[255] +GIT_DIFF_FIND_AND_BREAK_REWRITES: Literal[48] +GIT_DIFF_FIND_BY_CONFIG: Literal[0] +GIT_DIFF_FIND_COPIES: Literal[4] +GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED: Literal[8] +GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE: Literal[8192] +GIT_DIFF_FIND_EXACT_MATCH_ONLY: Literal[16384] +GIT_DIFF_FIND_FOR_UNTRACKED: Literal[64] +GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE: Literal[0] +GIT_DIFF_FIND_IGNORE_WHITESPACE: Literal[4096] +GIT_DIFF_FIND_REMOVE_UNMODIFIED: Literal[65536] +GIT_DIFF_FIND_RENAMES: Literal[1] +GIT_DIFF_FIND_RENAMES_FROM_REWRITES: Literal[2] +GIT_DIFF_FIND_REWRITES: Literal[16] +GIT_DIFF_FLAG_BINARY: Literal[1] +GIT_DIFF_FLAG_EXISTS: Literal[8] +GIT_DIFF_FLAG_NOT_BINARY: Literal[2] +GIT_DIFF_FLAG_VALID_ID: Literal[4] +GIT_DIFF_FLAG_VALID_SIZE: Literal[16] +GIT_DIFF_FORCE_BINARY: Literal[2097152] +GIT_DIFF_FORCE_TEXT: Literal[1048576] +GIT_DIFF_IGNORE_BLANK_LINES: Literal[524288] +GIT_DIFF_IGNORE_CASE: Literal[1024] +GIT_DIFF_IGNORE_FILEMODE: Literal[256] +GIT_DIFF_IGNORE_SUBMODULES: Literal[512] +GIT_DIFF_IGNORE_WHITESPACE: Literal[4194304] +GIT_DIFF_IGNORE_WHITESPACE_CHANGE: Literal[8388608] +GIT_DIFF_IGNORE_WHITESPACE_EOL: Literal[16777216] +GIT_DIFF_INCLUDE_CASECHANGE: Literal[2048] +GIT_DIFF_INCLUDE_IGNORED: Literal[2] +GIT_DIFF_INCLUDE_TYPECHANGE: Literal[64] +GIT_DIFF_INCLUDE_TYPECHANGE_TREES: Literal[128] +GIT_DIFF_INCLUDE_UNMODIFIED: Literal[32] +GIT_DIFF_INCLUDE_UNREADABLE: Literal[65536] +GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED: Literal[131072] +GIT_DIFF_INCLUDE_UNTRACKED: Literal[8] +GIT_DIFF_INDENT_HEURISTIC: Literal[262144] +GIT_DIFF_MINIMAL: Literal[536870912] +GIT_DIFF_NORMAL: Literal[0] +GIT_DIFF_PATIENCE: Literal[268435456] +GIT_DIFF_RECURSE_IGNORED_DIRS: Literal[4] +GIT_DIFF_RECURSE_UNTRACKED_DIRS: Literal[16] +GIT_DIFF_REVERSE: Literal[1] +GIT_DIFF_SHOW_BINARY: Literal[1073741824] +GIT_DIFF_SHOW_UNMODIFIED: Literal[67108864] +GIT_DIFF_SHOW_UNTRACKED_CONTENT: Literal[33554432] +GIT_DIFF_SKIP_BINARY_CHECK: Literal[8192] +GIT_DIFF_STATS_FULL: Literal[1] +GIT_DIFF_STATS_INCLUDE_SUMMARY: Literal[8] +GIT_DIFF_STATS_NONE: Literal[0] +GIT_DIFF_STATS_NUMBER: Literal[4] +GIT_DIFF_STATS_SHORT: Literal[2] +GIT_DIFF_UPDATE_INDEX: Literal[32768] +GIT_FILEMODE_BLOB: Literal[33188] +GIT_FILEMODE_BLOB_EXECUTABLE: Literal[33261] +GIT_FILEMODE_COMMIT: Literal[57344] +GIT_FILEMODE_LINK: Literal[40960] +GIT_FILEMODE_TREE: Literal[16384] +GIT_FILEMODE_UNREADABLE: Literal[0] +GIT_FILTER_ALLOW_UNSAFE: Literal[1] +GIT_FILTER_ATTRIBUTES_FROM_COMMIT: Literal[8] +GIT_FILTER_ATTRIBUTES_FROM_HEAD: Literal[4] +GIT_FILTER_CLEAN: Literal[1] +GIT_FILTER_DEFAULT: Literal[0] +GIT_FILTER_DRIVER_PRIORITY: Literal[200] +GIT_FILTER_NO_SYSTEM_ATTRIBUTES: Literal[2] +GIT_FILTER_SMUDGE: Literal[0] +GIT_FILTER_TO_ODB: Literal[1] +GIT_FILTER_TO_WORKTREE: Literal[0] +GIT_MERGE_ANALYSIS_FASTFORWARD: Literal[4] +GIT_MERGE_ANALYSIS_NONE: Literal[0] +GIT_MERGE_ANALYSIS_NORMAL: Literal[1] +GIT_MERGE_ANALYSIS_UNBORN: Literal[8] +GIT_MERGE_ANALYSIS_UP_TO_DATE: Literal[2] +GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY: Literal[2] +GIT_MERGE_PREFERENCE_NONE: Literal[0] +GIT_MERGE_PREFERENCE_NO_FASTFORWARD: Literal[1] +GIT_OBJECT_ANY: Literal[-2] +GIT_OBJECT_INVALID: Literal[-1] +GIT_OBJECT_OFS_DELTA: Literal[6] +GIT_OBJECT_REF_DELTA: Literal[7] +GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS: Literal[27] +GIT_OPT_ENABLE_CACHING: Literal[8] +GIT_OPT_ENABLE_FSYNC_GITDIR: Literal[19] +GIT_OPT_ENABLE_OFS_DELTA: Literal[18] +GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION: Literal[22] +GIT_OPT_ENABLE_STRICT_OBJECT_CREATION: Literal[14] +GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION: Literal[15] +GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY: Literal[24] +GIT_OPT_GET_CACHED_MEMORY: Literal[9] +GIT_OPT_GET_MWINDOW_FILE_LIMIT: Literal[29] +GIT_OPT_GET_MWINDOW_MAPPED_LIMIT: Literal[2] +GIT_OPT_GET_MWINDOW_SIZE: Literal[0] +GIT_OPT_GET_OWNER_VALIDATION: Literal[35] +GIT_OPT_GET_PACK_MAX_OBJECTS: Literal[25] +GIT_OPT_GET_SEARCH_PATH: Literal[4] +GIT_OPT_GET_TEMPLATE_PATH: Literal[10] +GIT_OPT_GET_USER_AGENT: Literal[17] +GIT_OPT_GET_WINDOWS_SHAREMODE: Literal[20] +GIT_OPT_SET_ALLOCATOR: Literal[23] +GIT_OPT_SET_CACHE_MAX_SIZE: Literal[7] +GIT_OPT_SET_CACHE_OBJECT_LIMIT: Literal[6] +GIT_OPT_SET_MWINDOW_FILE_LIMIT: Literal[30] +GIT_OPT_SET_MWINDOW_MAPPED_LIMIT: Literal[3] +GIT_OPT_SET_MWINDOW_SIZE: Literal[1] +GIT_OPT_SET_OWNER_VALIDATION: Literal[36] +GIT_OPT_SET_PACK_MAX_OBJECTS: Literal[26] +GIT_OPT_SET_SEARCH_PATH: Literal[5] +GIT_OPT_SET_SSL_CERT_LOCATIONS: Literal[12] +GIT_OPT_SET_SSL_CIPHERS: Literal[16] +GIT_OPT_SET_TEMPLATE_PATH: Literal[11] +GIT_OPT_SET_USER_AGENT: Literal[13] +GIT_OPT_SET_WINDOWS_SHAREMODE: Literal[21] +GIT_REFERENCES_ALL: Literal[0] +GIT_REFERENCES_BRANCHES: Literal[1] +GIT_REFERENCES_TAGS: Literal[2] +GIT_RESET_HARD: Literal[3] +GIT_RESET_MIXED: Literal[2] +GIT_RESET_SOFT: Literal[1] +GIT_REVSPEC_MERGE_BASE: Literal[4] +GIT_REVSPEC_RANGE: Literal[2] +GIT_REVSPEC_SINGLE: Literal[1] +GIT_SORT_NONE: Literal[0] +GIT_SORT_REVERSE: Literal[4] +GIT_SORT_TIME: Literal[2] +GIT_SORT_TOPOLOGICAL: Literal[1] +GIT_STASH_APPLY_DEFAULT: Literal[0] +GIT_STASH_APPLY_REINSTATE_INDEX: Literal[1] +GIT_STASH_DEFAULT: Literal[0] +GIT_STASH_INCLUDE_IGNORED: Literal[4] +GIT_STASH_INCLUDE_UNTRACKED: Literal[2] +GIT_STASH_KEEP_ALL: Literal[8] +GIT_STASH_KEEP_INDEX: Literal[1] +GIT_STATUS_CONFLICTED: Literal[32768] +GIT_STATUS_CURRENT: Literal[0] +GIT_STATUS_IGNORED: Literal[16384] +GIT_STATUS_INDEX_DELETED: Literal[4] +GIT_STATUS_INDEX_MODIFIED: Literal[2] +GIT_STATUS_INDEX_NEW: Literal[1] +GIT_STATUS_INDEX_RENAMED: Literal[8] +GIT_STATUS_INDEX_TYPECHANGE: Literal[16] +GIT_STATUS_WT_DELETED: Literal[512] +GIT_STATUS_WT_MODIFIED: Literal[256] +GIT_STATUS_WT_NEW: Literal[128] +GIT_STATUS_WT_RENAMED: Literal[2048] +GIT_STATUS_WT_TYPECHANGE: Literal[1024] +GIT_STATUS_WT_UNREADABLE: Literal[4096] +GIT_SUBMODULE_IGNORE_ALL: Literal[4] +GIT_SUBMODULE_IGNORE_DIRTY: Literal[3] +GIT_SUBMODULE_IGNORE_NONE: Literal[1] +GIT_SUBMODULE_IGNORE_UNSPECIFIED: Literal[-1] +GIT_SUBMODULE_IGNORE_UNTRACKED: Literal[2] +GIT_SUBMODULE_STATUS_INDEX_ADDED: Literal[16] +GIT_SUBMODULE_STATUS_INDEX_DELETED: Literal[32] +GIT_SUBMODULE_STATUS_INDEX_MODIFIED: Literal[64] +GIT_SUBMODULE_STATUS_IN_CONFIG: Literal[4] +GIT_SUBMODULE_STATUS_IN_HEAD: Literal[1] +GIT_SUBMODULE_STATUS_IN_INDEX: Literal[2] +GIT_SUBMODULE_STATUS_IN_WD: Literal[8] +GIT_SUBMODULE_STATUS_WD_ADDED: Literal[256] +GIT_SUBMODULE_STATUS_WD_DELETED: Literal[512] +GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED: Literal[2048] +GIT_SUBMODULE_STATUS_WD_MODIFIED: Literal[1024] +GIT_SUBMODULE_STATUS_WD_UNINITIALIZED: Literal[128] +GIT_SUBMODULE_STATUS_WD_UNTRACKED: Literal[8192] +GIT_SUBMODULE_STATUS_WD_WD_MODIFIED: Literal[4096] + +_OidArg: TypeAlias = 'str | Oid' + class Object: _pointer: bytes filemode: FileMode - hex: str id: Oid name: str | None - oid: Oid raw_name: bytes | None short_id: str - type: 'Literal[GIT_OBJ_COMMIT] | Literal[GIT_OBJ_TREE] | Literal[GIT_OBJ_TAG] | Literal[GIT_OBJ_BLOB]' + # GIT_OBJECT_COMMIT | GIT_OBJECT_TREE | GIT_OBJECT_TAG | GIT_OBJECT_BLOB + type: Literal[1, 2, 4, 3] type_str: "Literal['commit'] | Literal['tree'] | Literal['tag'] | Literal['blob']" @overload - def peel(self, target_type: 'Literal[GIT_OBJ_COMMIT]') -> 'Commit': ... + def peel(self, target_type: Literal[1] | type[Commit]) -> Commit: ... @overload - def peel(self, target_type: 'Literal[GIT_OBJ_TREE]') -> 'Tree': ... + def peel(self, target_type: Literal[2] | type[Tree]) -> Tree: ... @overload - def peel(self, target_type: 'Literal[GIT_OBJ_TAG]') -> 'Tag': ... + def peel(self, target_type: Literal[4] | type[Tag]) -> Tag: ... @overload - def peel(self, target_type: 'Literal[GIT_OBJ_BLOB]') -> 'Blob': ... + def peel(self, target_type: Literal[3] | type[Blob]) -> Blob: ... @overload - def peel(self, target_type: 'None') -> 'Commit|Tree|Blob': ... + def peel(self, target_type: None) -> Commit | Tree | Blob: ... def read_raw(self) -> bytes: ... - def __eq__(self, other) -> bool: ... - def __ge__(self, other) -> bool: ... - def __gt__(self, other) -> bool: ... + def __eq__(self, other: object) -> bool: ... + def __ge__(self, other: object) -> bool: ... + def __gt__(self, other: object) -> bool: ... def __hash__(self) -> int: ... - def __le__(self, other) -> bool: ... - def __lt__(self, other) -> bool: ... - def __ne__(self, other) -> bool: ... + def __le__(self, other: object) -> bool: ... + def __lt__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... class Reference: name: str @@ -72,28 +308,32 @@ class Reference: shorthand: str target: Oid | str type: ReferenceType - def __init__(self, *args) -> None: ... + + @overload + def __init__(self, name: str, target: str) -> None: ... + @overload + def __init__(self, name: str, oid: Oid, peel: Oid) -> None: ... def delete(self) -> None: ... def log(self) -> Iterator[RefLogEntry]: ... @overload - def peel(self, type: 'Literal[GIT_OBJ_COMMIT]') -> 'Commit': ... + def peel(self, type: Literal[1] | type[Commit]) -> Commit: ... @overload - def peel(self, type: 'Literal[GIT_OBJ_TREE]') -> 'Tree': ... + def peel(self, type: Literal[2] | type[Tree]) -> Tree: ... @overload - def peel(self, type: 'Literal[GIT_OBJ_TAG]') -> 'Tag': ... + def peel(self, type: Literal[4] | type[Tag]) -> Tag: ... @overload - def peel(self, type: 'Literal[GIT_OBJ_BLOB]') -> 'Blob': ... + def peel(self, type: Literal[3] | type[Blob]) -> Blob: ... @overload - def peel(self, type: 'None') -> 'Commit|Tree|Blob': ... + def peel(self, type: None) -> Commit | Tree | Blob: ... def rename(self, new_name: str) -> None: ... def resolve(self) -> Reference: ... def set_target(self, target: _OidArg, message: str = ...) -> None: ... - def __eq__(self, other) -> bool: ... - def __ge__(self, other) -> bool: ... - def __gt__(self, other) -> bool: ... - def __le__(self, other) -> bool: ... - def __lt__(self, other) -> bool: ... - def __ne__(self, other) -> bool: ... + def __eq__(self, other: object) -> bool: ... + def __ge__(self, other: object) -> bool: ... + def __gt__(self, other: object) -> bool: ... + def __le__(self, other: object) -> bool: ... + def __lt__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... class AlreadyExistsError(ValueError): ... @@ -125,7 +365,7 @@ class Branch(Reference): def delete(self) -> None: ... def is_checked_out(self) -> bool: ... def is_head(self) -> bool: ... - def rename(self, name: str, force: bool = False) -> None: ... + def rename(self, name: str, force: bool = False) -> None: ... # type: ignore class Commit(Object): author: Signature @@ -158,7 +398,7 @@ class Diff: ) -> None: ... def merge(self, diff: Diff) -> None: ... @staticmethod - def from_c(diff, repo) -> Diff: ... + def from_c(diff: Any, repo: Any) -> Diff: ... @staticmethod def parse_diff(git_diff: str | bytes) -> Diff: ... def __getitem__(self, index: int) -> Patch: ... # Diff_getitem @@ -183,7 +423,7 @@ class DiffFile: raw_path: bytes size: int @staticmethod - def from_c(bytes) -> DiffFile: ... + def from_c(bytes: bytes) -> DiffFile: ... class DiffHunk: header: str @@ -212,7 +452,7 @@ class GitError(Exception): ... class InvalidSpecError(ValueError): ... class Mailmap: - def __init__(self, *args) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... def add_entry( self, real_name: str = ..., @@ -237,7 +477,7 @@ class Note: class Odb: backends: Iterator[OdbBackend] - def __init__(self, *args, **kwargs) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... def add_backend(self, backend: OdbBackend, priority: int) -> None: ... def add_disk_alternate(self, path: str) -> None: ... def exists(self, oid: _OidArg) -> bool: ... @@ -247,7 +487,7 @@ class Odb: def __iter__(self) -> Iterator[Oid]: ... # Odb_as_iter class OdbBackend: - def __init__(self, *args, **kwargs) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... def exists(self, oid: _OidArg) -> bool: ... def exists_prefix(self, partial_id: _OidArg) -> Oid: ... def read(self, oid: _OidArg) -> tuple[int, bytes]: ... @@ -257,22 +497,22 @@ class OdbBackend: def __iter__(self) -> Iterator[Oid]: ... # OdbBackend_as_iter class OdbBackendLoose(OdbBackend): - def __init__(self, *args, **kwargs) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... class OdbBackendPack(OdbBackend): - def __init__(self, *args, **kwargs) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... class Oid: - hex: str raw: bytes def __init__(self, raw: bytes = ..., hex: str = ...) -> None: ... - def __eq__(self, other) -> bool: ... - def __ge__(self, other) -> bool: ... - def __gt__(self, other) -> bool: ... + def __eq__(self, other: object) -> bool: ... + def __ge__(self, other: object) -> bool: ... + def __gt__(self, other: object) -> bool: ... def __hash__(self) -> int: ... - def __le__(self, other) -> bool: ... - def __lt__(self, other) -> bool: ... - def __ne__(self, other) -> bool: ... + def __le__(self, other: object) -> bool: ... + def __lt__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + def __str__(self) -> str: ... class Patch: data: bytes @@ -297,10 +537,10 @@ class RefLogEntry: message: str oid_new: Oid oid_old: Oid - def __init__(self, *args, **kwargs) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... class Refdb: - def __init__(self, *args, **kwargs) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... def compress(self) -> None: ... @staticmethod def new(repo: Repository) -> Refdb: ... @@ -309,7 +549,7 @@ class Refdb: def set_backend(self, backend: RefdbBackend) -> None: ... class RefdbBackend: - def __init__(self, *args, **kwargs) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... def compress(self) -> None: ... def delete(self, ref_name: str, old_id: _OidArg, old_target: str) -> None: ... def ensure_log(self, ref_name: str) -> bool: ... @@ -330,7 +570,7 @@ class RefdbBackend: ) -> None: ... class RefdbFsBackend(RefdbBackend): - def __init__(self, *args, **kwargs) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... class Repository: _pointer: bytes @@ -345,10 +585,10 @@ class Repository: path: str refdb: Refdb workdir: str - def __init__(self, *args, **kwargs) -> None: ... + def __init__(self, *args: Any, **kwargs: Any) -> None: ... def TreeBuilder(self, src: Tree | _OidArg = ...) -> TreeBuilder: ... - def _disown(self, *args, **kwargs) -> None: ... - def _from_c(self, *args, **kwargs) -> None: ... + def _disown(self, *args: Any, **kwargs: Any) -> None: ... + def _from_c(self, *args: Any, **kwargs: Any) -> None: ... def add_worktree(self, name: str, path: str, ref: Reference = ...) -> Worktree: ... def applies( self, @@ -365,7 +605,9 @@ class Repository: def create_blob_fromdisk(self, path: str) -> Oid: ... def create_blob_fromiobase(self, iobase: IOBase) -> Oid: ... def create_blob_fromworkdir(self, path: str) -> Oid: ... - def create_branch(self, name: str, commit: Commit, force=False) -> Branch: ... + def create_branch( + self, name: str, commit: Commit, force: bool = False + ) -> Branch: ... def create_commit( self, reference_name: Optional[str], @@ -439,7 +681,7 @@ class Repository: def references_iterator_init(self) -> Iterator[Reference]: ... def references_iterator_next( self, - iter: Iterator, + iter: Iterator[Any], references_return_type: ReferenceFilter = ReferenceFilter.ALL, ) -> Reference: ... def reset(self, oid: _OidArg, reset_type: ResetMode) -> None: ... @@ -478,29 +720,29 @@ class Signature: offset: int = 0, encoding: Optional[str] = None, ) -> None: ... - def __eq__(self, other) -> bool: ... - def __ge__(self, other) -> bool: ... - def __gt__(self, other) -> bool: ... - def __le__(self, other) -> bool: ... - def __lt__(self, other) -> bool: ... - def __ne__(self, other) -> bool: ... + def __eq__(self, other: object) -> bool: ... + def __ge__(self, other: object) -> bool: ... + def __gt__(self, other: object) -> bool: ... + def __le__(self, other: object) -> bool: ... + def __lt__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... class Stash: commit_id: Oid message: str raw_message: bytes - def __eq__(self, other) -> bool: ... - def __ge__(self, other) -> bool: ... - def __gt__(self, other) -> bool: ... - def __le__(self, other) -> bool: ... - def __lt__(self, other) -> bool: ... - def __ne__(self, other) -> bool: ... + def __eq__(self, other: object) -> bool: ... + def __ge__(self, other: object) -> bool: ... + def __gt__(self, other: object) -> bool: ... + def __le__(self, other: object) -> bool: ... + def __lt__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... class Tag(Object): message: str - name: str + name: str | None raw_message: bytes - raw_name: bytes + raw_name: bytes | None tagger: Signature target: Oid def get_object(self) -> Object: ... @@ -555,7 +797,7 @@ class Worktree: is_prunable: bool name: str path: str - def prune(self, force=False) -> None: ... + def prune(self, force: bool = False) -> None: ... def discover_repository( path: str, across_fs: bool = False, ceiling_dirs: str = ... @@ -563,8 +805,6 @@ def discover_repository( def hash(data: bytes) -> Oid: ... def hashfile(path: str) -> Oid: ... def init_file_backend(path: str, flags: int = 0) -> object: ... -def option(opt: Option, *args) -> None: ... +def option(opt: Option, *args: Any) -> None: ... def reference_is_valid_name(refname: str) -> bool: ... def tree_entry_cmp(a: Object, b: Object) -> int: ... - -_OidArg = str | Oid From b53b9a775e52127b07564ec3cd519b616e1a424d Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 22:34:05 +0700 Subject: [PATCH 07/40] fix stubs --- pygit2/_libgit2.pyi | 2 +- pygit2/ffi.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pygit2/_libgit2.pyi b/pygit2/_libgit2.pyi index 2fb45d89..fdef4d9d 100644 --- a/pygit2/_libgit2.pyi +++ b/pygit2/_libgit2.pyi @@ -1,4 +1,4 @@ import _cffi_backend ffi: _cffi_backend.FFI -C: _cffi_backend.Lib +lib: _cffi_backend.Lib diff --git a/pygit2/ffi.py b/pygit2/ffi.py index 25814e0e..7d712195 100644 --- a/pygit2/ffi.py +++ b/pygit2/ffi.py @@ -26,3 +26,5 @@ # Import from pygit2 from ._libgit2 import ffi from ._libgit2 import lib as C + +__all__ = ["ffi", "C"] From c70241d6018bd720b865d30000c58ab839934e03 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 22:35:20 +0700 Subject: [PATCH 08/40] change lib to Any --- pygit2/_libgit2.pyi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pygit2/_libgit2.pyi b/pygit2/_libgit2.pyi index fdef4d9d..4e0c929a 100644 --- a/pygit2/_libgit2.pyi +++ b/pygit2/_libgit2.pyi @@ -1,4 +1,6 @@ +from typing import Any + import _cffi_backend ffi: _cffi_backend.FFI -lib: _cffi_backend.Lib +lib: Any From 42b5129ba9d8a05a5ceb704affd880e0148606af Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 22:39:23 +0700 Subject: [PATCH 09/40] fix pyright config --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 4f505542..e8f77358 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,3 +53,4 @@ quote-style = "single" [tool.pyright] typeCheckingMode = "strict" pythonVersion = "3.10" +reportPrivateUsage = "none" From 5f6657e7dd001e08b70e0f0c5a49959b3b816af7 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 22:44:17 +0700 Subject: [PATCH 10/40] fix _pygit2.pyi again --- pygit2/_pygit2.pyi | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/pygit2/_pygit2.pyi b/pygit2/_pygit2.pyi index 48bdabe2..dead6b66 100644 --- a/pygit2/_pygit2.pyi +++ b/pygit2/_pygit2.pyi @@ -282,15 +282,19 @@ class Object: type: Literal[1, 2, 4, 3] type_str: "Literal['commit'] | Literal['tree'] | Literal['tag'] | Literal['blob']" @overload - def peel(self, target_type: Literal[1] | type[Commit]) -> Commit: ... + def peel( + self, target_type: Literal[1, ObjectType.COMMIT] | type[Commit] + ) -> Commit: ... @overload - def peel(self, target_type: Literal[2] | type[Tree]) -> Tree: ... + def peel(self, target_type: Literal[2, ObjectType.TREE] | type[Tree]) -> Tree: ... @overload - def peel(self, target_type: Literal[4] | type[Tag]) -> Tag: ... + def peel(self, target_type: Literal[4, ObjectType.TAG] | type[Tag]) -> Tag: ... @overload - def peel(self, target_type: Literal[3] | type[Blob]) -> Blob: ... + def peel(self, target_type: Literal[3, ObjectType.BLOB] | type[Blob]) -> Blob: ... @overload - def peel(self, target_type: None) -> Commit | Tree | Blob: ... + def peel( + self, target_type: Literal[None, ObjectType.ANY] + ) -> Commit | Tree | Blob: ... def read_raw(self) -> bytes: ... def __eq__(self, other: object) -> bool: ... def __ge__(self, other: object) -> bool: ... @@ -318,13 +322,13 @@ class Reference: @overload def peel(self, type: Literal[1] | type[Commit]) -> Commit: ... @overload - def peel(self, type: Literal[2] | type[Tree]) -> Tree: ... + def peel(self, type: Literal[2, ObjectType.TREE] | type[Tree]) -> Tree: ... @overload - def peel(self, type: Literal[4] | type[Tag]) -> Tag: ... + def peel(self, type: Literal[4, ObjectType.TAG] | type[Tag]) -> Tag: ... @overload - def peel(self, type: Literal[3] | type[Blob]) -> Blob: ... + def peel(self, type: Literal[3, ObjectType.BLOB] | type[Blob]) -> Blob: ... @overload - def peel(self, type: None) -> Commit | Tree | Blob: ... + def peel(self, type: Literal[None, ObjectType.ANY]) -> Commit | Tree | Blob: ... def rename(self, new_name: str) -> None: ... def resolve(self) -> Reference: ... def set_target(self, target: _OidArg, message: str = ...) -> None: ... From 4b3878b6a2bc204752367951ef02e21d60619cc7 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 22:45:03 +0700 Subject: [PATCH 11/40] fix enums.py --- pygit2/enums.py | 173 ++++++++++++++++++++++++------------------------ 1 file changed, 87 insertions(+), 86 deletions(-) diff --git a/pygit2/enums.py b/pygit2/enums.py index e5bd54d9..f32d35d0 100644 --- a/pygit2/enums.py +++ b/pygit2/enums.py @@ -24,6 +24,7 @@ # Boston, MA 02110-1301, USA. from enum import IntEnum, IntFlag +from typing import cast from . import _pygit2 from .ffi import C @@ -52,12 +53,12 @@ class ApplyLocation(IntEnum): class AttrCheck(IntFlag): - FILE_THEN_INDEX = C.GIT_ATTR_CHECK_FILE_THEN_INDEX - INDEX_THEN_FILE = C.GIT_ATTR_CHECK_INDEX_THEN_FILE - INDEX_ONLY = C.GIT_ATTR_CHECK_INDEX_ONLY - NO_SYSTEM = C.GIT_ATTR_CHECK_NO_SYSTEM - INCLUDE_HEAD = C.GIT_ATTR_CHECK_INCLUDE_HEAD - INCLUDE_COMMIT = C.GIT_ATTR_CHECK_INCLUDE_COMMIT + FILE_THEN_INDEX = cast(int, C.GIT_ATTR_CHECK_FILE_THEN_INDEX) + INDEX_THEN_FILE = cast(int, C.GIT_ATTR_CHECK_INDEX_THEN_FILE) + INDEX_ONLY = cast(int, C.GIT_ATTR_CHECK_INDEX_ONLY) + NO_SYSTEM = cast(int, C.GIT_ATTR_CHECK_NO_SYSTEM) + INCLUDE_HEAD = cast(int, C.GIT_ATTR_CHECK_INCLUDE_HEAD) + INCLUDE_COMMIT = cast(int, C.GIT_ATTR_CHECK_INCLUDE_COMMIT) class BlameFlag(IntFlag): @@ -119,28 +120,28 @@ class CheckoutNotify(IntFlag): ones via `CheckoutCallbacks.checkout_notify_flags`. """ - NONE = C.GIT_CHECKOUT_NOTIFY_NONE + NONE = cast(int, C.GIT_CHECKOUT_NOTIFY_NONE) - CONFLICT = C.GIT_CHECKOUT_NOTIFY_CONFLICT + CONFLICT = cast(int, C.GIT_CHECKOUT_NOTIFY_CONFLICT) 'Invokes checkout on conflicting paths.' - DIRTY = C.GIT_CHECKOUT_NOTIFY_DIRTY + DIRTY = cast(int, C.GIT_CHECKOUT_NOTIFY_DIRTY) """ Notifies about "dirty" files, i.e. those that do not need an update but no longer match the baseline. Core git displays these files when checkout runs, but won't stop the checkout. """ - UPDATED = C.GIT_CHECKOUT_NOTIFY_UPDATED + UPDATED = cast(int, C.GIT_CHECKOUT_NOTIFY_UPDATED) 'Sends notification for any file changed.' - UNTRACKED = C.GIT_CHECKOUT_NOTIFY_UNTRACKED + UNTRACKED = cast(int, C.GIT_CHECKOUT_NOTIFY_UNTRACKED) 'Notifies about untracked files.' - IGNORED = C.GIT_CHECKOUT_NOTIFY_IGNORED + IGNORED = cast(int, C.GIT_CHECKOUT_NOTIFY_IGNORED) 'Notifies about ignored files.' - ALL = C.GIT_CHECKOUT_NOTIFY_ALL + ALL = cast(int, C.GIT_CHECKOUT_NOTIFY_ALL) class CheckoutStrategy(IntFlag): @@ -268,29 +269,29 @@ class CredentialType(IntFlag): authentication methods supported by the library. """ - USERPASS_PLAINTEXT = C.GIT_CREDENTIAL_USERPASS_PLAINTEXT + USERPASS_PLAINTEXT = cast(int, C.GIT_CREDENTIAL_USERPASS_PLAINTEXT) 'A vanilla user/password request' - SSH_KEY = C.GIT_CREDENTIAL_SSH_KEY + SSH_KEY = cast(int, C.GIT_CREDENTIAL_SSH_KEY) 'An SSH key-based authentication request' - SSH_CUSTOM = C.GIT_CREDENTIAL_SSH_CUSTOM + SSH_CUSTOM = cast(int, C.GIT_CREDENTIAL_SSH_CUSTOM) 'An SSH key-based authentication request, with a custom signature' - DEFAULT = C.GIT_CREDENTIAL_DEFAULT + DEFAULT = cast(int, C.GIT_CREDENTIAL_DEFAULT) 'An NTLM/Negotiate-based authentication request.' - SSH_INTERACTIVE = C.GIT_CREDENTIAL_SSH_INTERACTIVE + SSH_INTERACTIVE = cast(int, C.GIT_CREDENTIAL_SSH_INTERACTIVE) 'An SSH interactive authentication request.' - USERNAME = C.GIT_CREDENTIAL_USERNAME + USERNAME = cast(int, C.GIT_CREDENTIAL_USERNAME) """ Username-only authentication request. Used as a pre-authentication step if the underlying transport (eg. SSH, with no username in its URL) does not know which username to use. """ - SSH_MEMORY = C.GIT_CREDENTIAL_SSH_MEMORY + SSH_MEMORY = cast(int, C.GIT_CREDENTIAL_SSH_MEMORY) """ An SSH key-based authentication request. Allows credentials to be read from memory instead of files. @@ -651,23 +652,23 @@ class Feature(IntFlag): was compiled. """ - THREADS = C.GIT_FEATURE_THREADS - HTTPS = C.GIT_FEATURE_HTTPS - SSH = C.GIT_FEATURE_SSH - NSEC = C.GIT_FEATURE_NSEC + THREADS = cast(int, C.GIT_FEATURE_THREADS) + HTTPS = cast(int, C.GIT_FEATURE_HTTPS) + SSH = cast(int, C.GIT_FEATURE_SSH) + NSEC = cast(int, C.GIT_FEATURE_NSEC) class FetchPrune(IntEnum): """Acceptable prune settings when fetching.""" - UNSPECIFIED = C.GIT_FETCH_PRUNE_UNSPECIFIED + UNSPECIFIED = cast(int, C.GIT_FETCH_PRUNE_UNSPECIFIED) 'Use the setting from the configuration' - PRUNE = C.GIT_FETCH_PRUNE + PRUNE = cast(int, C.GIT_FETCH_PRUNE) """Force pruning on: remove any remote branch in the local repository that does not exist in the remote.""" - NO_PRUNE = C.GIT_FETCH_NO_PRUNE + NO_PRUNE = cast(int, C.GIT_FETCH_NO_PRUNE) """Force pruning off: always keep the remote branches.""" @@ -783,7 +784,7 @@ class MergeFavor(IntEnum): merging functionality how to deal with conflicting regions of the files. """ - NORMAL = C.GIT_MERGE_FILE_FAVOR_NORMAL + NORMAL = cast(int, C.GIT_MERGE_FILE_FAVOR_NORMAL) """ When a region of a file is changed in both branches, a conflict will be recorded in the index so that `checkout` can produce a merge file with @@ -792,7 +793,7 @@ class MergeFavor(IntEnum): This is the default. """ - OURS = C.GIT_MERGE_FILE_FAVOR_OURS + OURS = cast(int, C.GIT_MERGE_FILE_FAVOR_OURS) """ When a region of a file is changed in both branches, the file created in the index will contain the "ours" side of any conflicting region. @@ -800,7 +801,7 @@ class MergeFavor(IntEnum): The index will not record a conflict. """ - THEIRS = C.GIT_MERGE_FILE_FAVOR_THEIRS + THEIRS = cast(int, C.GIT_MERGE_FILE_FAVOR_THEIRS) """ When a region of a file is changed in both branches, the file created in the index will contain the "theirs" side of any conflicting region. @@ -808,7 +809,7 @@ class MergeFavor(IntEnum): The index will not record a conflict. """ - UNION = C.GIT_MERGE_FILE_FAVOR_UNION + UNION = cast(int, C.GIT_MERGE_FILE_FAVOR_UNION) """ When a region of a file is changed in both branches, the file created in the index will contain each unique line from each side, @@ -821,37 +822,37 @@ class MergeFavor(IntEnum): class MergeFileFlag(IntFlag): """File merging flags""" - DEFAULT = C.GIT_MERGE_FILE_DEFAULT + DEFAULT = cast(int, C.GIT_MERGE_FILE_DEFAULT) """ Defaults """ - STYLE_MERGE = C.GIT_MERGE_FILE_STYLE_MERGE + STYLE_MERGE = cast(int, C.GIT_MERGE_FILE_STYLE_MERGE) """ Create standard conflicted merge files """ - STYLE_DIFF3 = C.GIT_MERGE_FILE_STYLE_DIFF3 + STYLE_DIFF3 = cast(int, C.GIT_MERGE_FILE_STYLE_DIFF3) """ Create diff3-style files """ - SIMPLIFY_ALNUM = C.GIT_MERGE_FILE_SIMPLIFY_ALNUM + SIMPLIFY_ALNUM = cast(int, C.GIT_MERGE_FILE_SIMPLIFY_ALNUM) """ Condense non-alphanumeric regions for simplified diff file """ - IGNORE_WHITESPACE = C.GIT_MERGE_FILE_IGNORE_WHITESPACE + IGNORE_WHITESPACE = cast(int, C.GIT_MERGE_FILE_IGNORE_WHITESPACE) """ Ignore all whitespace """ - IGNORE_WHITESPACE_CHANGE = C.GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE + IGNORE_WHITESPACE_CHANGE = cast(int, C.GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE) """ Ignore changes in amount of whitespace """ - IGNORE_WHITESPACE_EOL = C.GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL + IGNORE_WHITESPACE_EOL = cast(int, C.GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL) """ Ignore whitespace at end of line """ - DIFF_PATIENCE = C.GIT_MERGE_FILE_DIFF_PATIENCE + DIFF_PATIENCE = cast(int, C.GIT_MERGE_FILE_DIFF_PATIENCE) """ Use the "patience diff" algorithm """ - DIFF_MINIMAL = C.GIT_MERGE_FILE_DIFF_MINIMAL + DIFF_MINIMAL = cast(int, C.GIT_MERGE_FILE_DIFF_MINIMAL) """ Take extra time to find minimal diff """ - STYLE_ZDIFF3 = C.GIT_MERGE_FILE_STYLE_ZDIFF3 + STYLE_ZDIFF3 = cast(int, C.GIT_MERGE_FILE_STYLE_ZDIFF3) """ Create zdiff3 ("zealous diff3")-style files """ - ACCEPT_CONFLICTS = C.GIT_MERGE_FILE_ACCEPT_CONFLICTS + ACCEPT_CONFLICTS = cast(int, C.GIT_MERGE_FILE_ACCEPT_CONFLICTS) """ Do not produce file conflicts when common regions have changed; keep the conflict markers in the file and accept that as the merge result. @@ -864,26 +865,26 @@ class MergeFlag(IntFlag): A combination of these flags can be passed in via the `flags` value. """ - FIND_RENAMES = C.GIT_MERGE_FIND_RENAMES + FIND_RENAMES = cast(int, C.GIT_MERGE_FIND_RENAMES) """ Detect renames that occur between the common ancestor and the "ours" side or the common ancestor and the "theirs" side. This will enable the ability to merge between a modified and renamed file. """ - FAIL_ON_CONFLICT = C.GIT_MERGE_FAIL_ON_CONFLICT + FAIL_ON_CONFLICT = cast(int, C.GIT_MERGE_FAIL_ON_CONFLICT) """ If a conflict occurs, exit immediately instead of attempting to continue resolving conflicts. The merge operation will raise GitError (GIT_EMERGECONFLICT) and no index will be returned. """ - SKIP_REUC = C.GIT_MERGE_SKIP_REUC + SKIP_REUC = cast(int, C.GIT_MERGE_SKIP_REUC) """ Do not write the REUC extension on the generated index. """ - NO_RECURSIVE = C.GIT_MERGE_NO_RECURSIVE + NO_RECURSIVE = cast(int, C.GIT_MERGE_NO_RECURSIVE) """ If the commits being merged have multiple merge bases, do not build a recursive merge base (by merging the multiple merge bases), @@ -891,7 +892,7 @@ class MergeFlag(IntFlag): merge base to `git-merge-resolve`. """ - VIRTUAL_BASE = C.GIT_MERGE_VIRTUAL_BASE + VIRTUAL_BASE = cast(int, C.GIT_MERGE_VIRTUAL_BASE) """ Treat this merge as if it is to produce the virtual base of a recursive merge. This will ensure that there are no conflicts, any conflicting @@ -1006,16 +1007,16 @@ class ReferenceFilter(IntEnum): class ReferenceType(IntFlag): """Basic type of any Git reference.""" - INVALID = C.GIT_REFERENCE_INVALID + INVALID = cast(int, C.GIT_REFERENCE_INVALID) 'Invalid reference' - DIRECT = C.GIT_REFERENCE_DIRECT + DIRECT = cast(int, C.GIT_REFERENCE_DIRECT) 'A reference that points at an object id' - SYMBOLIC = C.GIT_REFERENCE_SYMBOLIC + SYMBOLIC = cast(int, C.GIT_REFERENCE_SYMBOLIC) 'A reference that points at another reference' - ALL = C.GIT_REFERENCE_ALL + ALL = cast(int, C.GIT_REFERENCE_ALL) 'Bitwise OR of (DIRECT | SYMBOLIC)' @@ -1024,33 +1025,33 @@ class RepositoryInitFlag(IntFlag): Option flags for pygit2.init_repository(). """ - BARE = C.GIT_REPOSITORY_INIT_BARE + BARE = cast(int, C.GIT_REPOSITORY_INIT_BARE) 'Create a bare repository with no working directory.' - NO_REINIT = C.GIT_REPOSITORY_INIT_NO_REINIT + NO_REINIT = cast(int, C.GIT_REPOSITORY_INIT_NO_REINIT) 'Raise GitError if the path appears to already be a git repository.' - NO_DOTGIT_DIR = C.GIT_REPOSITORY_INIT_NO_DOTGIT_DIR + NO_DOTGIT_DIR = cast(int, C.GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) """Normally a "/.git/" will be appended to the repo path for non-bare repos (if it is not already there), but passing this flag prevents that behavior.""" - MKDIR = C.GIT_REPOSITORY_INIT_MKDIR + MKDIR = cast(int, C.GIT_REPOSITORY_INIT_MKDIR) """Make the repo_path (and workdir_path) as needed. Init is always willing to create the ".git" directory even without this flag. This flag tells init to create the trailing component of the repo and workdir paths as needed.""" - MKPATH = C.GIT_REPOSITORY_INIT_MKPATH + MKPATH = cast(int, C.GIT_REPOSITORY_INIT_MKPATH) 'Recursively make all components of the repo and workdir paths as necessary.' - EXTERNAL_TEMPLATE = C.GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE + EXTERNAL_TEMPLATE = cast(int, C.GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) """libgit2 normally uses internal templates to initialize a new repo. This flags enables external templates, looking at the "template_path" from the options if set, or the `init.templatedir` global config if not, or falling back on "/usr/share/git-core/templates" if it exists.""" - RELATIVE_GITLINK = C.GIT_REPOSITORY_INIT_RELATIVE_GITLINK + RELATIVE_GITLINK = cast(int, C.GIT_REPOSITORY_INIT_RELATIVE_GITLINK) """If an alternate workdir is specified, use relative paths for the gitdir and core.worktree.""" @@ -1060,16 +1061,16 @@ class RepositoryInitMode(IntEnum): Mode options for pygit2.init_repository(). """ - SHARED_UMASK = C.GIT_REPOSITORY_INIT_SHARED_UMASK + SHARED_UMASK = cast(int, C.GIT_REPOSITORY_INIT_SHARED_UMASK) 'Use permissions configured by umask - the default.' - SHARED_GROUP = C.GIT_REPOSITORY_INIT_SHARED_GROUP + SHARED_GROUP = cast(int, C.GIT_REPOSITORY_INIT_SHARED_GROUP) """ Use '--shared=group' behavior, chmod'ing the new repo to be group writable and "g+sx" for sticky group assignment. """ - SHARED_ALL = C.GIT_REPOSITORY_INIT_SHARED_ALL + SHARED_ALL = cast(int, C.GIT_REPOSITORY_INIT_SHARED_ALL) "Use '--shared=all' behavior, adding world readability." @@ -1081,14 +1082,14 @@ class RepositoryOpenFlag(IntFlag): DEFAULT = 0 'Default flags.' - NO_SEARCH = C.GIT_REPOSITORY_OPEN_NO_SEARCH + NO_SEARCH = cast(int, C.GIT_REPOSITORY_OPEN_NO_SEARCH) """ Only open the repository if it can be immediately found in the start_path. Do not walk up from the start_path looking at parent directories. """ - CROSS_FS = C.GIT_REPOSITORY_OPEN_CROSS_FS + CROSS_FS = cast(int, C.GIT_REPOSITORY_OPEN_CROSS_FS) """ Unless this flag is set, open will not continue searching across filesystem boundaries (i.e. when `st_dev` changes from the `stat` @@ -1097,21 +1098,21 @@ class RepositoryOpenFlag(IntFlag): "/" is a different filesystem than "/home". """ - BARE = C.GIT_REPOSITORY_OPEN_BARE + BARE = cast(int, C.GIT_REPOSITORY_OPEN_BARE) """ Open repository as a bare repo regardless of core.bare config, and defer loading config file for faster setup. Unlike `git_repository_open_bare`, this can follow gitlinks. """ - NO_DOTGIT = C.GIT_REPOSITORY_OPEN_NO_DOTGIT + NO_DOTGIT = cast(int, C.GIT_REPOSITORY_OPEN_NO_DOTGIT) """ Do not check for a repository by appending /.git to the start_path; only open the repository if start_path itself points to the git directory. """ - FROM_ENV = C.GIT_REPOSITORY_OPEN_FROM_ENV + FROM_ENV = cast(int, C.GIT_REPOSITORY_OPEN_FROM_ENV) """ Find and open a git repository, respecting the environment variables used by the git command-line tools. @@ -1135,18 +1136,18 @@ class RepositoryState(IntEnum): to be in, based on the current operation which is ongoing. """ - NONE = C.GIT_REPOSITORY_STATE_NONE - MERGE = C.GIT_REPOSITORY_STATE_MERGE - REVERT = C.GIT_REPOSITORY_STATE_REVERT - REVERT_SEQUENCE = C.GIT_REPOSITORY_STATE_REVERT_SEQUENCE - CHERRYPICK = C.GIT_REPOSITORY_STATE_CHERRYPICK - CHERRYPICK_SEQUENCE = C.GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE - BISECT = C.GIT_REPOSITORY_STATE_BISECT - REBASE = C.GIT_REPOSITORY_STATE_REBASE - REBASE_INTERACTIVE = C.GIT_REPOSITORY_STATE_REBASE_INTERACTIVE - REBASE_MERGE = C.GIT_REPOSITORY_STATE_REBASE_MERGE - APPLY_MAILBOX = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX - APPLY_MAILBOX_OR_REBASE = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE + NONE = cast(int, C.GIT_REPOSITORY_STATE_NONE) + MERGE = cast(int, C.GIT_REPOSITORY_STATE_MERGE) + REVERT = cast(int, C.GIT_REPOSITORY_STATE_REVERT) + REVERT_SEQUENCE = cast(int, C.GIT_REPOSITORY_STATE_REVERT_SEQUENCE) + CHERRYPICK = cast(int, C.GIT_REPOSITORY_STATE_CHERRYPICK) + CHERRYPICK_SEQUENCE = cast(int, C.GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE) + BISECT = cast(int, C.GIT_REPOSITORY_STATE_BISECT) + REBASE = cast(int, C.GIT_REPOSITORY_STATE_REBASE) + REBASE_INTERACTIVE = cast(int, C.GIT_REPOSITORY_STATE_REBASE_INTERACTIVE) + REBASE_MERGE = cast(int, C.GIT_REPOSITORY_STATE_REBASE_MERGE) + APPLY_MAILBOX = cast(int, C.GIT_REPOSITORY_STATE_APPLY_MAILBOX) + APPLY_MAILBOX_OR_REBASE = cast(int, C.GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE) class ResetMode(IntEnum): @@ -1214,27 +1215,27 @@ class StashApplyProgress(IntEnum): Stash apply progression states """ - NONE = C.GIT_STASH_APPLY_PROGRESS_NONE + NONE = cast(int, C.GIT_STASH_APPLY_PROGRESS_NONE) - LOADING_STASH = C.GIT_STASH_APPLY_PROGRESS_LOADING_STASH + LOADING_STASH = cast(int, C.GIT_STASH_APPLY_PROGRESS_LOADING_STASH) 'Loading the stashed data from the object database.' - ANALYZE_INDEX = C.GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX + ANALYZE_INDEX = cast(int, C.GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX) 'The stored index is being analyzed.' - ANALYZE_MODIFIED = C.GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED + ANALYZE_MODIFIED = cast(int, C.GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED) 'The modified files are being analyzed.' - ANALYZE_UNTRACKED = C.GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED + ANALYZE_UNTRACKED = cast(int, C.GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED) 'The untracked and ignored files are being analyzed.' - CHECKOUT_UNTRACKED = C.GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED + CHECKOUT_UNTRACKED = cast(int, C.GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED) 'The untracked files are being written to disk.' - CHECKOUT_MODIFIED = C.GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED + CHECKOUT_MODIFIED = cast(int, C.GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED) 'The modified files are being written to disk.' - DONE = C.GIT_STASH_APPLY_PROGRESS_DONE + DONE = cast(int, C.GIT_STASH_APPLY_PROGRESS_DONE) 'The stash was applied successfully.' From 49bc71b2e912a832c64c342f14b0425706179905 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 22:58:30 +0700 Subject: [PATCH 12/40] add FilterSource --- pygit2/_pygit2.pyi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pygit2/_pygit2.pyi b/pygit2/_pygit2.pyi index dead6b66..ba4ec393 100644 --- a/pygit2/_pygit2.pyi +++ b/pygit2/_pygit2.pyi @@ -11,6 +11,8 @@ from .enums import ( DiffOption, DiffStatsFormat, FileMode, + FilterFlag, + FilterMode, MergeAnalysis, MergePreference, ObjectType, @@ -803,6 +805,14 @@ class Worktree: path: str def prune(self, force: bool = False) -> None: ... +class FilterSource: + filemode: int + flags: FilterFlag + mode: FilterMode + oid: Oid | None + path: str + repo: Repository + def discover_repository( path: str, across_fs: bool = False, ceiling_dirs: str = ... ) -> str | None: ... From 7433683e1fc647646a68524efcf8a8570d32f9c6 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 23:02:05 +0700 Subject: [PATCH 13/40] yet another fix the _pygit2.pyi --- pygit2/_pygit2.pyi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pygit2/_pygit2.pyi b/pygit2/_pygit2.pyi index ba4ec393..8626cd0c 100644 --- a/pygit2/_pygit2.pyi +++ b/pygit2/_pygit2.pyi @@ -1,5 +1,5 @@ from io import IOBase -from typing import Any, Iterator, Literal, Optional, TypeAlias, overload +from typing import Any, Callable, Iterator, Literal, Optional, TypeAlias, overload from . import Index from .enums import ( @@ -822,3 +822,5 @@ def init_file_backend(path: str, flags: int = 0) -> object: ... def option(opt: Option, *args: Any) -> None: ... def reference_is_valid_name(refname: str) -> bool: ... def tree_entry_cmp(a: Object, b: Object) -> int: ... + +_cache_enums: Callable[..., None] From 3aabbc7c6f8b09345b8d2254fa1e67877c194f01 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 23:08:01 +0700 Subject: [PATCH 14/40] add typing to credentials.py --- pygit2/credentials.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/pygit2/credentials.py b/pygit2/credentials.py index f16aac4a..03c374e1 100644 --- a/pygit2/credentials.py +++ b/pygit2/credentials.py @@ -23,8 +23,19 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. +from __future__ import annotations + +from typing import Any, Protocol + from .enums import CredentialType -from .ffi import C + + +class BaseCredentials(Protocol): + @property + def credential_type(self) -> CredentialType: ... + @property + def credential_tuple(self) -> tuple[str, ...]: ... + def __call__(self, _url: Any, _username: Any, _allowed: Any) -> BaseCredentials: ... class Username: @@ -34,7 +45,7 @@ class Username: callback and for returning from said callback. """ - def __init__(self, username): + def __init__(self, username: str): self._username = username @property @@ -45,7 +56,7 @@ def credential_type(self) -> CredentialType: def credential_tuple(self): return (self._username,) - def __call__(self, _url, _username, _allowed): + def __call__(self, _url: Any, _username: Any, _allowed: Any): return self @@ -56,7 +67,7 @@ class UserPass: callback and for returning from said callback. """ - def __init__(self, username, password): + def __init__(self, username: str, password: str): self._username = username self._password = password @@ -68,7 +79,7 @@ def credential_type(self) -> CredentialType: def credential_tuple(self): return (self._username, self._password) - def __call__(self, _url, _username, _allowed): + def __call__(self, _url: Any, _username: Any, _allowed: Any): return self @@ -95,7 +106,13 @@ class Keypair: no passphrase is required. """ - def __init__(self, username, pubkey, privkey, passphrase): + def __init__( + self, + username: str, + pubkey: str | None, + privkey: str | None, + passphrase: str | None, + ): self._username = username self._pubkey = pubkey self._privkey = privkey @@ -109,12 +126,12 @@ def credential_type(self) -> CredentialType: def credential_tuple(self): return (self._username, self._pubkey, self._privkey, self._passphrase) - def __call__(self, _url, _username, _allowed): + def __call__(self, _url: Any, _username: Any, _allowed: Any): return self class KeypairFromAgent(Keypair): - def __init__(self, username): + def __init__(self, username: str): super().__init__(username, None, None, None) From 9a1affc9fbc1b09aba2722d86603c0f69b044a06 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 23:10:49 +0700 Subject: [PATCH 15/40] add typing to errors.py --- pygit2/errors.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pygit2/errors.py b/pygit2/errors.py index 53108072..c4aff076 100644 --- a/pygit2/errors.py +++ b/pygit2/errors.py @@ -30,7 +30,7 @@ value_errors = {C.GIT_EEXISTS, C.GIT_EINVALIDSPEC, C.GIT_EAMBIGUOUS} -def check_error(err, io=False): +def check_error(err: int, io: bool = False) -> None: if err >= 0: return @@ -41,7 +41,9 @@ def check_error(err, io=False): # Error message giterr = C.git_error_last() if giterr != ffi.NULL: - message = ffi.string(giterr.message).decode('utf8') + message = ffi.string(giterr.message) + if isinstance(message, bytes): + message = message.decode('utf8') else: message = f'err {err} (no message provided)' @@ -66,6 +68,6 @@ def check_error(err, io=False): # Indicate that we want libgit2 to pretend a function was not set -class Passthrough(Exception): +class Passthrough(NotImplementedError): def __init__(self): super().__init__('The function asked for pass-through') From 735ba5a6283b388034c402d9b11d87d56fa4de62 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 23:12:35 +0700 Subject: [PATCH 16/40] fix pyproject again --- pyproject.toml | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e8f77358..3e07c3b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ skip = "pp3* *musllinux_aarch64 *musllinux_ppc64le" archs = ["auto"] build-frontend = "default" dependency-versions = "pinned" -environment = {LIBGIT2_VERSION="1.8.4", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.2.3", LIBGIT2="/project/ci"} +environment = { LIBGIT2_VERSION = "1.8.4", LIBSSH2_VERSION = "1.11.1", OPENSSL_VERSION = "3.2.3", LIBGIT2 = "/project/ci" } before-all = "sh build.sh" @@ -21,19 +21,27 @@ repair-wheel-command = "LD_LIBRARY_PATH=/project/ci/lib auditwheel repair -w {de [tool.cibuildwheel.macos] archs = ["universal2"] -environment = {LIBGIT2_VERSION="1.8.4", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.2.3", LIBGIT2="/Users/runner/work/pygit2/pygit2/ci"} +environment = { LIBGIT2_VERSION = "1.8.4", LIBSSH2_VERSION = "1.11.1", OPENSSL_VERSION = "3.2.3", LIBGIT2 = "/Users/runner/work/pygit2/pygit2/ci" } repair-wheel-command = "DYLD_LIBRARY_PATH=/Users/runner/work/pygit2/pygit2/ci/lib delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}" [tool.ruff] -target-version = "py310" # oldest supported Python version +target-version = "py310" # oldest supported Python version fix = true -extend-exclude = [ - ".cache", - ".coverage", - "build", - "venv*", +extend-exclude = [".cache", ".coverage", "build", "venv*"] +lint.select = [ + "C", + "E", + "W", + "F", + "I", + "B", + "C4", + "ARG", + "SIM", + "PTH", + "PL", + "TID", ] -lint.select = ["C", "E", "W", "F", "I", "B", "C4", "ARG", "SIM", "PTH", "PL", "TID"] lint.ignore = [ "W291", # Trailing whitespace "E501", # Line too long @@ -44,7 +52,8 @@ lint.ignore = [ "PLW0603", # Global statement "PLR0913", # Too many arguments "B010", # setattr - "F401" # unused imports + "F401", # unused imports + "ARG002", # unused arguments ] [tool.ruff.format] From 5fc3b70fe0315a9b08d3527eec50bf0bb755d82f Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 23:15:35 +0700 Subject: [PATCH 17/40] add filter_* functions to _pygit2.pyi --- pygit2/_pygit2.pyi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pygit2/_pygit2.pyi b/pygit2/_pygit2.pyi index 8626cd0c..f745f289 100644 --- a/pygit2/_pygit2.pyi +++ b/pygit2/_pygit2.pyi @@ -1,6 +1,8 @@ from io import IOBase from typing import Any, Callable, Iterator, Literal, Optional, TypeAlias, overload +from pygit2.filter import Filter + from . import Index from .enums import ( ApplyLocation, @@ -822,5 +824,9 @@ def init_file_backend(path: str, flags: int = 0) -> object: ... def option(opt: Option, *args: Any) -> None: ... def reference_is_valid_name(refname: str) -> bool: ... def tree_entry_cmp(a: Object, b: Object) -> int: ... +def filter_register( + name: str, filter_cls: type[Filter], priority: int = GIT_FILTER_DRIVER_PRIORITY +) -> None: ... +def filter_unregister(name: str) -> None: ... _cache_enums: Callable[..., None] From 95b003f0ddf8b5cee73c63922ad3acb21144a438 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 23:28:08 +0700 Subject: [PATCH 18/40] add typing to utils.py --- pygit2/utils.py | 60 +++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/pygit2/utils.py b/pygit2/utils.py index bf6d7ead..fa220467 100644 --- a/pygit2/utils.py +++ b/pygit2/utils.py @@ -23,21 +23,33 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. +from __future__ import annotations + import contextlib import os +from types import TracebackType +from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast # Import from pygit2 from .ffi import C, ffi +if TYPE_CHECKING: + from _typeshed import SupportsLenAndGetItem + +_T = TypeVar('_T') + -def maybe_string(ptr): +def maybe_string(ptr: Any) -> str | None: if not ptr: return None - return ffi.string(ptr).decode('utf8') + out = ffi.string(ptr) + if isinstance(out, bytes): + out = out.decode('utf8') + return out -def to_bytes(s, encoding='utf-8', errors='strict'): +def to_bytes(s: Any, encoding: str = 'utf-8', errors: str = 'strict') -> bytes | Any: if s == ffi.NULL or s is None: return ffi.NULL @@ -50,27 +62,27 @@ def to_bytes(s, encoding='utf-8', errors='strict'): return s.encode(encoding, errors) -def to_str(s): +def to_str(s: Any) -> str: if hasattr(s, '__fspath__'): s = os.fspath(s) - if type(s) is str: + if isinstance(s, str): return s - if type(s) is bytes: + if isinstance(s, bytes): return s.decode() raise TypeError(f'unexpected type "{repr(s)}"') -def ptr_to_bytes(ptr_cdata): +def ptr_to_bytes(ptr_cdata: Any) -> bytes: """ Convert a pointer coming from C code () to a byte buffer containing the address that the pointer refers to. """ pp = ffi.new('void **', ptr_cdata) - return bytes(ffi.buffer(pp)[:]) + return bytes(ffi.buffer(pp)[:]) # type: ignore @contextlib.contextmanager @@ -80,7 +92,7 @@ def new_git_strarray(): C.git_strarray_dispose(strarray) -def strarray_to_strings(arr): +def strarray_to_strings(arr: Any) -> list[str]: """ Return a list of strings from a git_strarray pointer. @@ -88,7 +100,7 @@ def strarray_to_strings(arr): calling this function. """ try: - return [ffi.string(arr.strings[i]).decode('utf-8') for i in range(arr.count)] + return [ffi.string(arr.strings[i]).decode('utf-8') for i in range(arr.count)] # type: ignore finally: C.git_strarray_dispose(arr) @@ -113,18 +125,20 @@ class StrArray: contents of 'struct' only remain valid within the StrArray context. """ - def __init__(self, l): + def __init__(self, listarg: Any): # Allow passing in None as lg2 typically considers them the same as empty - if l is None: + if listarg is None: self.__array = ffi.NULL return - if not isinstance(l, (list, tuple)): + if not isinstance(listarg, (list, tuple)): raise TypeError('Value must be a list') - strings = [None] * len(l) - for i in range(len(l)): - li = l[i] + listarg = cast(list[Any], listarg) + + strings: list[Any] = [None] * len(listarg) + for i in range(len(listarg)): + li = listarg[i] if not isinstance(li, str) and not hasattr(li, '__fspath__'): raise TypeError('Value must be a string or PathLike object') @@ -137,14 +151,16 @@ def __init__(self, l): def __enter__(self): return self - def __exit__(self, type, value, traceback): + def __exit__( + self, type: type[BaseException], value: BaseException, traceback: TracebackType + ) -> None: pass @property def ptr(self): return self.__array - def assign_to(self, git_strarray): + def assign_to(self, git_strarray: Any): if self.__array == ffi.NULL: git_strarray.strings = ffi.NULL git_strarray.count = 0 @@ -153,22 +169,22 @@ def assign_to(self, git_strarray): git_strarray.count = len(self.__strings) -class GenericIterator: +class GenericIterator(Generic[_T]): """Helper to easily implement an iterator. The constructor gets a container which must implement __len__ and __getitem__ """ - def __init__(self, container): + def __init__(self, container: SupportsLenAndGetItem[_T]): self.container = container self.length = len(container) self.idx = 0 - def next(self): + def next(self) -> _T: return self.__next__() - def __next__(self): + def __next__(self) -> _T: idx = self.idx if idx >= self.length: raise StopIteration From e71d03ba175818184ffe926a95c29c2f582933d0 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 23:29:31 +0700 Subject: [PATCH 19/40] fix ffi.py --- pygit2/ffi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygit2/ffi.py b/pygit2/ffi.py index 7d712195..1fb809fb 100644 --- a/pygit2/ffi.py +++ b/pygit2/ffi.py @@ -27,4 +27,4 @@ from ._libgit2 import ffi from ._libgit2 import lib as C -__all__ = ["ffi", "C"] +__all__ = ['ffi', 'C'] From 9b68da868e6577b7c2b1c13928acbbdc2b808c08 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sat, 21 Dec 2024 23:29:42 +0700 Subject: [PATCH 20/40] initial commit of pygit2 __init__ --- pygit2/__init__.py | 758 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 755 insertions(+), 3 deletions(-) diff --git a/pygit2/__init__.py b/pygit2/__init__.py index e245184c..e1d7655e 100644 --- a/pygit2/__init__.py +++ b/pygit2/__init__.py @@ -34,7 +34,297 @@ # Low level API from ._pygit2 import * -from ._pygit2 import _cache_enums +from ._pygit2 import ( + GIT_APPLY_LOCATION_BOTH, + GIT_APPLY_LOCATION_INDEX, + GIT_APPLY_LOCATION_WORKDIR, + GIT_BLAME_FIRST_PARENT, + GIT_BLAME_IGNORE_WHITESPACE, + GIT_BLAME_NORMAL, + GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES, + GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES, + GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES, + GIT_BLAME_TRACK_COPIES_SAME_FILE, + GIT_BLAME_USE_MAILMAP, + GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT, + GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD, + GIT_BLOB_FILTER_CHECK_FOR_BINARY, + GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES, + GIT_BRANCH_ALL, + GIT_BRANCH_LOCAL, + GIT_BRANCH_REMOTE, + GIT_CHECKOUT_ALLOW_CONFLICTS, + GIT_CHECKOUT_CONFLICT_STYLE_DIFF3, + GIT_CHECKOUT_CONFLICT_STYLE_MERGE, + GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3, + GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH, + GIT_CHECKOUT_DONT_OVERWRITE_IGNORED, + GIT_CHECKOUT_DONT_REMOVE_EXISTING, + GIT_CHECKOUT_DONT_UPDATE_INDEX, + GIT_CHECKOUT_DONT_WRITE_INDEX, + GIT_CHECKOUT_DRY_RUN, + GIT_CHECKOUT_FORCE, + GIT_CHECKOUT_NO_REFRESH, + GIT_CHECKOUT_NONE, + GIT_CHECKOUT_RECREATE_MISSING, + GIT_CHECKOUT_REMOVE_IGNORED, + GIT_CHECKOUT_REMOVE_UNTRACKED, + GIT_CHECKOUT_SAFE, + GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES, + GIT_CHECKOUT_SKIP_UNMERGED, + GIT_CHECKOUT_UPDATE_ONLY, + GIT_CHECKOUT_USE_OURS, + GIT_CHECKOUT_USE_THEIRS, + GIT_CONFIG_HIGHEST_LEVEL, + GIT_CONFIG_LEVEL_APP, + GIT_CONFIG_LEVEL_GLOBAL, + GIT_CONFIG_LEVEL_LOCAL, + GIT_CONFIG_LEVEL_PROGRAMDATA, + GIT_CONFIG_LEVEL_SYSTEM, + GIT_CONFIG_LEVEL_WORKTREE, + GIT_CONFIG_LEVEL_XDG, + GIT_DELTA_ADDED, + GIT_DELTA_CONFLICTED, + GIT_DELTA_COPIED, + GIT_DELTA_DELETED, + GIT_DELTA_IGNORED, + GIT_DELTA_MODIFIED, + GIT_DELTA_RENAMED, + GIT_DELTA_TYPECHANGE, + GIT_DELTA_UNMODIFIED, + GIT_DELTA_UNREADABLE, + GIT_DELTA_UNTRACKED, + GIT_DESCRIBE_ALL, + GIT_DESCRIBE_DEFAULT, + GIT_DESCRIBE_TAGS, + GIT_DIFF_BREAK_REWRITES, + GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY, + GIT_DIFF_DISABLE_PATHSPEC_MATCH, + GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS, + GIT_DIFF_FIND_ALL, + GIT_DIFF_FIND_AND_BREAK_REWRITES, + GIT_DIFF_FIND_BY_CONFIG, + GIT_DIFF_FIND_COPIES, + GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED, + GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE, + GIT_DIFF_FIND_EXACT_MATCH_ONLY, + GIT_DIFF_FIND_FOR_UNTRACKED, + GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE, + GIT_DIFF_FIND_IGNORE_WHITESPACE, + GIT_DIFF_FIND_REMOVE_UNMODIFIED, + GIT_DIFF_FIND_RENAMES, + GIT_DIFF_FIND_RENAMES_FROM_REWRITES, + GIT_DIFF_FIND_REWRITES, + GIT_DIFF_FLAG_BINARY, + GIT_DIFF_FLAG_EXISTS, + GIT_DIFF_FLAG_NOT_BINARY, + GIT_DIFF_FLAG_VALID_ID, + GIT_DIFF_FLAG_VALID_SIZE, + GIT_DIFF_FORCE_BINARY, + GIT_DIFF_FORCE_TEXT, + GIT_DIFF_IGNORE_BLANK_LINES, + GIT_DIFF_IGNORE_CASE, + GIT_DIFF_IGNORE_FILEMODE, + GIT_DIFF_IGNORE_SUBMODULES, + GIT_DIFF_IGNORE_WHITESPACE, + GIT_DIFF_IGNORE_WHITESPACE_CHANGE, + GIT_DIFF_IGNORE_WHITESPACE_EOL, + GIT_DIFF_INCLUDE_CASECHANGE, + GIT_DIFF_INCLUDE_IGNORED, + GIT_DIFF_INCLUDE_TYPECHANGE, + GIT_DIFF_INCLUDE_TYPECHANGE_TREES, + GIT_DIFF_INCLUDE_UNMODIFIED, + GIT_DIFF_INCLUDE_UNREADABLE, + GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED, + GIT_DIFF_INCLUDE_UNTRACKED, + GIT_DIFF_INDENT_HEURISTIC, + GIT_DIFF_MINIMAL, + GIT_DIFF_NORMAL, + GIT_DIFF_PATIENCE, + GIT_DIFF_RECURSE_IGNORED_DIRS, + GIT_DIFF_RECURSE_UNTRACKED_DIRS, + GIT_DIFF_REVERSE, + GIT_DIFF_SHOW_BINARY, + GIT_DIFF_SHOW_UNMODIFIED, + GIT_DIFF_SHOW_UNTRACKED_CONTENT, + GIT_DIFF_SKIP_BINARY_CHECK, + GIT_DIFF_STATS_FULL, + GIT_DIFF_STATS_INCLUDE_SUMMARY, + GIT_DIFF_STATS_NONE, + GIT_DIFF_STATS_NUMBER, + GIT_DIFF_STATS_SHORT, + GIT_DIFF_UPDATE_INDEX, + GIT_FILEMODE_BLOB, + GIT_FILEMODE_BLOB_EXECUTABLE, + GIT_FILEMODE_COMMIT, + GIT_FILEMODE_LINK, + GIT_FILEMODE_TREE, + GIT_FILEMODE_UNREADABLE, + GIT_FILTER_ALLOW_UNSAFE, + GIT_FILTER_ATTRIBUTES_FROM_COMMIT, + GIT_FILTER_ATTRIBUTES_FROM_HEAD, + GIT_FILTER_CLEAN, + GIT_FILTER_DEFAULT, + GIT_FILTER_DRIVER_PRIORITY, + GIT_FILTER_NO_SYSTEM_ATTRIBUTES, + GIT_FILTER_SMUDGE, + GIT_FILTER_TO_ODB, + GIT_FILTER_TO_WORKTREE, + GIT_MERGE_ANALYSIS_FASTFORWARD, + GIT_MERGE_ANALYSIS_NONE, + GIT_MERGE_ANALYSIS_NORMAL, + GIT_MERGE_ANALYSIS_UNBORN, + GIT_MERGE_ANALYSIS_UP_TO_DATE, + GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY, + GIT_MERGE_PREFERENCE_NO_FASTFORWARD, + GIT_MERGE_PREFERENCE_NONE, + GIT_OBJECT_ANY, + GIT_OBJECT_BLOB, + GIT_OBJECT_COMMIT, + GIT_OBJECT_INVALID, + GIT_OBJECT_OFS_DELTA, + GIT_OBJECT_REF_DELTA, + GIT_OBJECT_TAG, + GIT_OBJECT_TREE, + GIT_OID_HEX_ZERO, + GIT_OID_HEXSZ, + GIT_OID_MINPREFIXLEN, + GIT_OID_RAWSZ, + GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS, + GIT_OPT_ENABLE_CACHING, + GIT_OPT_ENABLE_FSYNC_GITDIR, + GIT_OPT_ENABLE_OFS_DELTA, + GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, + GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, + GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, + GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY, + GIT_OPT_GET_CACHED_MEMORY, + GIT_OPT_GET_MWINDOW_FILE_LIMIT, + GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, + GIT_OPT_GET_MWINDOW_SIZE, + GIT_OPT_GET_OWNER_VALIDATION, + GIT_OPT_GET_PACK_MAX_OBJECTS, + GIT_OPT_GET_SEARCH_PATH, + GIT_OPT_GET_TEMPLATE_PATH, + GIT_OPT_GET_USER_AGENT, + GIT_OPT_GET_WINDOWS_SHAREMODE, + GIT_OPT_SET_ALLOCATOR, + GIT_OPT_SET_CACHE_MAX_SIZE, + GIT_OPT_SET_CACHE_OBJECT_LIMIT, + GIT_OPT_SET_MWINDOW_FILE_LIMIT, + GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, + GIT_OPT_SET_MWINDOW_SIZE, + GIT_OPT_SET_OWNER_VALIDATION, + GIT_OPT_SET_PACK_MAX_OBJECTS, + GIT_OPT_SET_SEARCH_PATH, + GIT_OPT_SET_SSL_CERT_LOCATIONS, + GIT_OPT_SET_SSL_CIPHERS, + GIT_OPT_SET_TEMPLATE_PATH, + GIT_OPT_SET_USER_AGENT, + GIT_OPT_SET_WINDOWS_SHAREMODE, + GIT_REFERENCES_ALL, + GIT_REFERENCES_BRANCHES, + GIT_REFERENCES_TAGS, + GIT_RESET_HARD, + GIT_RESET_MIXED, + GIT_RESET_SOFT, + GIT_REVSPEC_MERGE_BASE, + GIT_REVSPEC_RANGE, + GIT_REVSPEC_SINGLE, + GIT_SORT_NONE, + GIT_SORT_REVERSE, + GIT_SORT_TIME, + GIT_SORT_TOPOLOGICAL, + GIT_STASH_APPLY_DEFAULT, + GIT_STASH_APPLY_REINSTATE_INDEX, + GIT_STASH_DEFAULT, + GIT_STASH_INCLUDE_IGNORED, + GIT_STASH_INCLUDE_UNTRACKED, + GIT_STASH_KEEP_ALL, + GIT_STASH_KEEP_INDEX, + GIT_STATUS_CONFLICTED, + GIT_STATUS_CURRENT, + GIT_STATUS_IGNORED, + GIT_STATUS_INDEX_DELETED, + GIT_STATUS_INDEX_MODIFIED, + GIT_STATUS_INDEX_NEW, + GIT_STATUS_INDEX_RENAMED, + GIT_STATUS_INDEX_TYPECHANGE, + GIT_STATUS_WT_DELETED, + GIT_STATUS_WT_MODIFIED, + GIT_STATUS_WT_NEW, + GIT_STATUS_WT_RENAMED, + GIT_STATUS_WT_TYPECHANGE, + GIT_STATUS_WT_UNREADABLE, + GIT_SUBMODULE_IGNORE_ALL, + GIT_SUBMODULE_IGNORE_DIRTY, + GIT_SUBMODULE_IGNORE_NONE, + GIT_SUBMODULE_IGNORE_UNSPECIFIED, + GIT_SUBMODULE_IGNORE_UNTRACKED, + GIT_SUBMODULE_STATUS_IN_CONFIG, + GIT_SUBMODULE_STATUS_IN_HEAD, + GIT_SUBMODULE_STATUS_IN_INDEX, + GIT_SUBMODULE_STATUS_IN_WD, + GIT_SUBMODULE_STATUS_INDEX_ADDED, + GIT_SUBMODULE_STATUS_INDEX_DELETED, + GIT_SUBMODULE_STATUS_INDEX_MODIFIED, + GIT_SUBMODULE_STATUS_WD_ADDED, + GIT_SUBMODULE_STATUS_WD_DELETED, + GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED, + GIT_SUBMODULE_STATUS_WD_MODIFIED, + GIT_SUBMODULE_STATUS_WD_UNINITIALIZED, + GIT_SUBMODULE_STATUS_WD_UNTRACKED, + GIT_SUBMODULE_STATUS_WD_WD_MODIFIED, + LIBGIT2_VER_MAJOR, + LIBGIT2_VER_MINOR, + LIBGIT2_VER_REVISION, + LIBGIT2_VERSION, + AlreadyExistsError, + Blob, + Branch, + Commit, + Diff, + DiffDelta, + DiffFile, + DiffHunk, + DiffLine, + DiffStats, + FilterSource, + GitError, + InvalidSpecError, + Mailmap, + Note, + Object, + Odb, + OdbBackend, + OdbBackendLoose, + OdbBackendPack, + Oid, + Patch, + Refdb, + RefdbBackend, + RefdbFsBackend, + Reference, + RefLogEntry, + RevSpec, + Signature, + Stash, + Tag, + Tree, + TreeBuilder, + Walker, + Worktree, + _cache_enums, + discover_repository, + filter_register, + filter_unregister, + hash, + hashfile, + init_file_backend, + option, + reference_is_valid_name, + tree_entry_cmp, +) from .blame import Blame, BlameHunk from .blob import BlobIO from .callbacks import ( @@ -47,12 +337,81 @@ git_fetch_options, ) from .config import Config -from .credentials import * +from .credentials import ( + Keypair, + KeypairFromAgent, + KeypairFromMemory, + Username, + UserPass, +) from .errors import Passthrough, check_error from .ffi import C, ffi from .filter import Filter from .index import Index, IndexEntry -from .legacyenums import * +from .legacyenums import ( + GIT_ATTR_CHECK_FILE_THEN_INDEX, + GIT_ATTR_CHECK_INCLUDE_COMMIT, + GIT_ATTR_CHECK_INCLUDE_HEAD, + GIT_ATTR_CHECK_INDEX_ONLY, + GIT_ATTR_CHECK_INDEX_THEN_FILE, + GIT_ATTR_CHECK_NO_SYSTEM, + GIT_CHECKOUT_NOTIFY_ALL, + GIT_CHECKOUT_NOTIFY_CONFLICT, + GIT_CHECKOUT_NOTIFY_DIRTY, + GIT_CHECKOUT_NOTIFY_IGNORED, + GIT_CHECKOUT_NOTIFY_NONE, + GIT_CHECKOUT_NOTIFY_UNTRACKED, + GIT_CHECKOUT_NOTIFY_UPDATED, + GIT_CREDENTIAL_DEFAULT, + GIT_CREDENTIAL_SSH_CUSTOM, + GIT_CREDENTIAL_SSH_INTERACTIVE, + GIT_CREDENTIAL_SSH_KEY, + GIT_CREDENTIAL_SSH_MEMORY, + GIT_CREDENTIAL_USERNAME, + GIT_CREDENTIAL_USERPASS_PLAINTEXT, + GIT_FEATURE_HTTPS, + GIT_FEATURE_NSEC, + GIT_FEATURE_SSH, + GIT_FEATURE_THREADS, + GIT_FETCH_NO_PRUNE, + GIT_FETCH_PRUNE, + GIT_FETCH_PRUNE_UNSPECIFIED, + GIT_REPOSITORY_INIT_BARE, + GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE, + GIT_REPOSITORY_INIT_MKDIR, + GIT_REPOSITORY_INIT_MKPATH, + GIT_REPOSITORY_INIT_NO_DOTGIT_DIR, + GIT_REPOSITORY_INIT_NO_REINIT, + GIT_REPOSITORY_INIT_RELATIVE_GITLINK, + GIT_REPOSITORY_INIT_SHARED_ALL, + GIT_REPOSITORY_INIT_SHARED_GROUP, + GIT_REPOSITORY_INIT_SHARED_UMASK, + GIT_REPOSITORY_OPEN_BARE, + GIT_REPOSITORY_OPEN_CROSS_FS, + GIT_REPOSITORY_OPEN_FROM_ENV, + GIT_REPOSITORY_OPEN_NO_DOTGIT, + GIT_REPOSITORY_OPEN_NO_SEARCH, + GIT_REPOSITORY_STATE_APPLY_MAILBOX, + GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE, + GIT_REPOSITORY_STATE_BISECT, + GIT_REPOSITORY_STATE_CHERRYPICK, + GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE, + GIT_REPOSITORY_STATE_MERGE, + GIT_REPOSITORY_STATE_NONE, + GIT_REPOSITORY_STATE_REBASE, + GIT_REPOSITORY_STATE_REBASE_INTERACTIVE, + GIT_REPOSITORY_STATE_REBASE_MERGE, + GIT_REPOSITORY_STATE_REVERT, + GIT_REPOSITORY_STATE_REVERT_SEQUENCE, + GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX, + GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED, + GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED, + GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED, + GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED, + GIT_STASH_APPLY_PROGRESS_DONE, + GIT_STASH_APPLY_PROGRESS_LOADING_STASH, + GIT_STASH_APPLY_PROGRESS_NONE, +) from .packbuilder import PackBuilder from .remotes import Remote from .repository import Repository @@ -60,6 +419,399 @@ from .submodules import Submodule from .utils import to_bytes, to_str +__all__ = [ + 'AlreadyExistsError', + 'Blame', + 'BlameHunk', + 'Blob', + 'BlobIO', + 'Branch', + 'C', + 'CheckoutCallbacks', + 'Commit', + 'Config', + # 'CredentialType', + 'Diff', + 'DiffDelta', + 'DiffFile', + 'DiffHunk', + 'DiffLine', + 'DiffStats', + 'Filter', + 'FilterSource', + 'GIT_APPLY_LOCATION_BOTH', + 'GIT_APPLY_LOCATION_INDEX', + 'GIT_APPLY_LOCATION_WORKDIR', + 'GIT_ATTR_CHECK_FILE_THEN_INDEX', + 'GIT_ATTR_CHECK_INCLUDE_COMMIT', + 'GIT_ATTR_CHECK_INCLUDE_HEAD', + 'GIT_ATTR_CHECK_INDEX_ONLY', + 'GIT_ATTR_CHECK_INDEX_THEN_FILE', + 'GIT_ATTR_CHECK_NO_SYSTEM', + 'GIT_BLAME_FIRST_PARENT', + 'GIT_BLAME_IGNORE_WHITESPACE', + 'GIT_BLAME_NORMAL', + 'GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES', + 'GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES', + 'GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES', + 'GIT_BLAME_TRACK_COPIES_SAME_FILE', + 'GIT_BLAME_USE_MAILMAP', + 'GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT', + 'GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD', + 'GIT_BLOB_FILTER_CHECK_FOR_BINARY', + 'GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES', + 'GIT_BRANCH_ALL', + 'GIT_BRANCH_LOCAL', + 'GIT_BRANCH_REMOTE', + 'GIT_CHECKOUT_ALLOW_CONFLICTS', + 'GIT_CHECKOUT_CONFLICT_STYLE_DIFF3', + 'GIT_CHECKOUT_CONFLICT_STYLE_MERGE', + 'GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3', + 'GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH', + 'GIT_CHECKOUT_DONT_OVERWRITE_IGNORED', + 'GIT_CHECKOUT_DONT_REMOVE_EXISTING', + 'GIT_CHECKOUT_DONT_UPDATE_INDEX', + 'GIT_CHECKOUT_DONT_WRITE_INDEX', + 'GIT_CHECKOUT_DRY_RUN', + 'GIT_CHECKOUT_FORCE', + 'GIT_CHECKOUT_NONE', + 'GIT_CHECKOUT_NOTIFY_ALL', + 'GIT_CHECKOUT_NOTIFY_CONFLICT', + 'GIT_CHECKOUT_NOTIFY_DIRTY', + 'GIT_CHECKOUT_NOTIFY_IGNORED', + 'GIT_CHECKOUT_NOTIFY_NONE', + 'GIT_CHECKOUT_NOTIFY_UNTRACKED', + 'GIT_CHECKOUT_NOTIFY_UPDATED', + 'GIT_CHECKOUT_NO_REFRESH', + 'GIT_CHECKOUT_RECREATE_MISSING', + 'GIT_CHECKOUT_REMOVE_IGNORED', + 'GIT_CHECKOUT_REMOVE_UNTRACKED', + 'GIT_CHECKOUT_SAFE', + 'GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES', + 'GIT_CHECKOUT_SKIP_UNMERGED', + 'GIT_CHECKOUT_UPDATE_ONLY', + 'GIT_CHECKOUT_USE_OURS', + 'GIT_CHECKOUT_USE_THEIRS', + 'GIT_CONFIG_HIGHEST_LEVEL', + 'GIT_CONFIG_LEVEL_APP', + 'GIT_CONFIG_LEVEL_GLOBAL', + 'GIT_CONFIG_LEVEL_LOCAL', + 'GIT_CONFIG_LEVEL_PROGRAMDATA', + 'GIT_CONFIG_LEVEL_SYSTEM', + 'GIT_CONFIG_LEVEL_WORKTREE', + 'GIT_CONFIG_LEVEL_XDG', + 'GIT_CREDENTIAL_DEFAULT', + 'GIT_CREDENTIAL_SSH_CUSTOM', + 'GIT_CREDENTIAL_SSH_INTERACTIVE', + 'GIT_CREDENTIAL_SSH_KEY', + 'GIT_CREDENTIAL_SSH_MEMORY', + 'GIT_CREDENTIAL_USERNAME', + 'GIT_CREDENTIAL_USERPASS_PLAINTEXT', + 'GIT_DELTA_ADDED', + 'GIT_DELTA_CONFLICTED', + 'GIT_DELTA_COPIED', + 'GIT_DELTA_DELETED', + 'GIT_DELTA_IGNORED', + 'GIT_DELTA_MODIFIED', + 'GIT_DELTA_RENAMED', + 'GIT_DELTA_TYPECHANGE', + 'GIT_DELTA_UNMODIFIED', + 'GIT_DELTA_UNREADABLE', + 'GIT_DELTA_UNTRACKED', + 'GIT_DESCRIBE_ALL', + 'GIT_DESCRIBE_DEFAULT', + 'GIT_DESCRIBE_TAGS', + 'GIT_DIFF_BREAK_REWRITES', + 'GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY', + 'GIT_DIFF_DISABLE_PATHSPEC_MATCH', + 'GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS', + 'GIT_DIFF_FIND_ALL', + 'GIT_DIFF_FIND_AND_BREAK_REWRITES', + 'GIT_DIFF_FIND_BY_CONFIG', + 'GIT_DIFF_FIND_COPIES', + 'GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED', + 'GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE', + 'GIT_DIFF_FIND_EXACT_MATCH_ONLY', + 'GIT_DIFF_FIND_FOR_UNTRACKED', + 'GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE', + 'GIT_DIFF_FIND_IGNORE_WHITESPACE', + 'GIT_DIFF_FIND_REMOVE_UNMODIFIED', + 'GIT_DIFF_FIND_RENAMES', + 'GIT_DIFF_FIND_RENAMES_FROM_REWRITES', + 'GIT_DIFF_FIND_REWRITES', + 'GIT_DIFF_FLAG_BINARY', + 'GIT_DIFF_FLAG_EXISTS', + 'GIT_DIFF_FLAG_NOT_BINARY', + 'GIT_DIFF_FLAG_VALID_ID', + 'GIT_DIFF_FLAG_VALID_SIZE', + 'GIT_DIFF_FORCE_BINARY', + 'GIT_DIFF_FORCE_TEXT', + 'GIT_DIFF_IGNORE_BLANK_LINES', + 'GIT_DIFF_IGNORE_CASE', + 'GIT_DIFF_IGNORE_FILEMODE', + 'GIT_DIFF_IGNORE_SUBMODULES', + 'GIT_DIFF_IGNORE_WHITESPACE', + 'GIT_DIFF_IGNORE_WHITESPACE_CHANGE', + 'GIT_DIFF_IGNORE_WHITESPACE_EOL', + 'GIT_DIFF_INCLUDE_CASECHANGE', + 'GIT_DIFF_INCLUDE_IGNORED', + 'GIT_DIFF_INCLUDE_TYPECHANGE', + 'GIT_DIFF_INCLUDE_TYPECHANGE_TREES', + 'GIT_DIFF_INCLUDE_UNMODIFIED', + 'GIT_DIFF_INCLUDE_UNREADABLE', + 'GIT_DIFF_INCLUDE_UNREADABLE_AS_UNTRACKED', + 'GIT_DIFF_INCLUDE_UNTRACKED', + 'GIT_DIFF_INDENT_HEURISTIC', + 'GIT_DIFF_MINIMAL', + 'GIT_DIFF_NORMAL', + 'GIT_DIFF_PATIENCE', + 'GIT_DIFF_RECURSE_IGNORED_DIRS', + 'GIT_DIFF_RECURSE_UNTRACKED_DIRS', + 'GIT_DIFF_REVERSE', + 'GIT_DIFF_SHOW_BINARY', + 'GIT_DIFF_SHOW_UNMODIFIED', + 'GIT_DIFF_SHOW_UNTRACKED_CONTENT', + 'GIT_DIFF_SKIP_BINARY_CHECK', + 'GIT_DIFF_STATS_FULL', + 'GIT_DIFF_STATS_INCLUDE_SUMMARY', + 'GIT_DIFF_STATS_NONE', + 'GIT_DIFF_STATS_NUMBER', + 'GIT_DIFF_STATS_SHORT', + 'GIT_DIFF_UPDATE_INDEX', + 'GIT_FEATURE_HTTPS', + 'GIT_FEATURE_NSEC', + 'GIT_FEATURE_SSH', + 'GIT_FEATURE_THREADS', + 'GIT_FETCH_NO_PRUNE', + 'GIT_FETCH_PRUNE', + 'GIT_FETCH_PRUNE_UNSPECIFIED', + 'GIT_FILEMODE_BLOB', + 'GIT_FILEMODE_BLOB_EXECUTABLE', + 'GIT_FILEMODE_COMMIT', + 'GIT_FILEMODE_LINK', + 'GIT_FILEMODE_TREE', + 'GIT_FILEMODE_UNREADABLE', + 'GIT_FILTER_ALLOW_UNSAFE', + 'GIT_FILTER_ATTRIBUTES_FROM_COMMIT', + 'GIT_FILTER_ATTRIBUTES_FROM_HEAD', + 'GIT_FILTER_CLEAN', + 'GIT_FILTER_DEFAULT', + 'GIT_FILTER_DRIVER_PRIORITY', + 'GIT_FILTER_NO_SYSTEM_ATTRIBUTES', + 'GIT_FILTER_SMUDGE', + 'GIT_FILTER_TO_ODB', + 'GIT_FILTER_TO_WORKTREE', + 'GIT_MERGE_ANALYSIS_FASTFORWARD', + 'GIT_MERGE_ANALYSIS_NONE', + 'GIT_MERGE_ANALYSIS_NORMAL', + 'GIT_MERGE_ANALYSIS_UNBORN', + 'GIT_MERGE_ANALYSIS_UP_TO_DATE', + 'GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY', + 'GIT_MERGE_PREFERENCE_NONE', + 'GIT_MERGE_PREFERENCE_NO_FASTFORWARD', + 'GIT_OBJECT_ANY', + 'GIT_OBJECT_BLOB', + 'GIT_OBJECT_COMMIT', + 'GIT_OBJECT_INVALID', + 'GIT_OBJECT_OFS_DELTA', + 'GIT_OBJECT_REF_DELTA', + 'GIT_OBJECT_TAG', + 'GIT_OBJECT_TREE', + 'GIT_OID_HEXSZ', + 'GIT_OID_HEX_ZERO', + 'GIT_OID_MINPREFIXLEN', + 'GIT_OID_RAWSZ', + 'GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS', + 'GIT_OPT_ENABLE_CACHING', + 'GIT_OPT_ENABLE_FSYNC_GITDIR', + 'GIT_OPT_ENABLE_OFS_DELTA', + 'GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION', + 'GIT_OPT_ENABLE_STRICT_OBJECT_CREATION', + 'GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION', + 'GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY', + 'GIT_OPT_GET_CACHED_MEMORY', + 'GIT_OPT_GET_MWINDOW_FILE_LIMIT', + 'GIT_OPT_GET_MWINDOW_MAPPED_LIMIT', + 'GIT_OPT_GET_MWINDOW_SIZE', + 'GIT_OPT_GET_OWNER_VALIDATION', + 'GIT_OPT_GET_PACK_MAX_OBJECTS', + 'GIT_OPT_GET_SEARCH_PATH', + 'GIT_OPT_GET_TEMPLATE_PATH', + 'GIT_OPT_GET_USER_AGENT', + 'GIT_OPT_GET_WINDOWS_SHAREMODE', + 'GIT_OPT_SET_ALLOCATOR', + 'GIT_OPT_SET_CACHE_MAX_SIZE', + 'GIT_OPT_SET_CACHE_OBJECT_LIMIT', + 'GIT_OPT_SET_MWINDOW_FILE_LIMIT', + 'GIT_OPT_SET_MWINDOW_MAPPED_LIMIT', + 'GIT_OPT_SET_MWINDOW_SIZE', + 'GIT_OPT_SET_OWNER_VALIDATION', + 'GIT_OPT_SET_PACK_MAX_OBJECTS', + 'GIT_OPT_SET_SEARCH_PATH', + 'GIT_OPT_SET_SSL_CERT_LOCATIONS', + 'GIT_OPT_SET_SSL_CIPHERS', + 'GIT_OPT_SET_TEMPLATE_PATH', + 'GIT_OPT_SET_USER_AGENT', + 'GIT_OPT_SET_WINDOWS_SHAREMODE', + 'GIT_REFERENCES_ALL', + 'GIT_REFERENCES_BRANCHES', + 'GIT_REFERENCES_TAGS', + 'GIT_REPOSITORY_INIT_BARE', + 'GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE', + 'GIT_REPOSITORY_INIT_MKDIR', + 'GIT_REPOSITORY_INIT_MKPATH', + 'GIT_REPOSITORY_INIT_NO_DOTGIT_DIR', + 'GIT_REPOSITORY_INIT_NO_REINIT', + 'GIT_REPOSITORY_INIT_RELATIVE_GITLINK', + 'GIT_REPOSITORY_INIT_SHARED_ALL', + 'GIT_REPOSITORY_INIT_SHARED_GROUP', + 'GIT_REPOSITORY_INIT_SHARED_UMASK', + 'GIT_REPOSITORY_OPEN_BARE', + 'GIT_REPOSITORY_OPEN_CROSS_FS', + 'GIT_REPOSITORY_OPEN_FROM_ENV', + 'GIT_REPOSITORY_OPEN_NO_DOTGIT', + 'GIT_REPOSITORY_OPEN_NO_SEARCH', + 'GIT_REPOSITORY_STATE_APPLY_MAILBOX', + 'GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE', + 'GIT_REPOSITORY_STATE_BISECT', + 'GIT_REPOSITORY_STATE_CHERRYPICK', + 'GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE', + 'GIT_REPOSITORY_STATE_MERGE', + 'GIT_REPOSITORY_STATE_NONE', + 'GIT_REPOSITORY_STATE_REBASE', + 'GIT_REPOSITORY_STATE_REBASE_INTERACTIVE', + 'GIT_REPOSITORY_STATE_REBASE_MERGE', + 'GIT_REPOSITORY_STATE_REVERT', + 'GIT_REPOSITORY_STATE_REVERT_SEQUENCE', + 'GIT_RESET_HARD', + 'GIT_RESET_MIXED', + 'GIT_RESET_SOFT', + 'GIT_REVSPEC_MERGE_BASE', + 'GIT_REVSPEC_RANGE', + 'GIT_REVSPEC_SINGLE', + 'GIT_SORT_NONE', + 'GIT_SORT_REVERSE', + 'GIT_SORT_TIME', + 'GIT_SORT_TOPOLOGICAL', + 'GIT_STASH_APPLY_DEFAULT', + 'GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX', + 'GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED', + 'GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED', + 'GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED', + 'GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED', + 'GIT_STASH_APPLY_PROGRESS_DONE', + 'GIT_STASH_APPLY_PROGRESS_LOADING_STASH', + 'GIT_STASH_APPLY_PROGRESS_NONE', + 'GIT_STASH_APPLY_REINSTATE_INDEX', + 'GIT_STASH_DEFAULT', + 'GIT_STASH_INCLUDE_IGNORED', + 'GIT_STASH_INCLUDE_UNTRACKED', + 'GIT_STASH_KEEP_ALL', + 'GIT_STASH_KEEP_INDEX', + 'GIT_STATUS_CONFLICTED', + 'GIT_STATUS_CURRENT', + 'GIT_STATUS_IGNORED', + 'GIT_STATUS_INDEX_DELETED', + 'GIT_STATUS_INDEX_MODIFIED', + 'GIT_STATUS_INDEX_NEW', + 'GIT_STATUS_INDEX_RENAMED', + 'GIT_STATUS_INDEX_TYPECHANGE', + 'GIT_STATUS_WT_DELETED', + 'GIT_STATUS_WT_MODIFIED', + 'GIT_STATUS_WT_NEW', + 'GIT_STATUS_WT_RENAMED', + 'GIT_STATUS_WT_TYPECHANGE', + 'GIT_STATUS_WT_UNREADABLE', + 'GIT_SUBMODULE_IGNORE_ALL', + 'GIT_SUBMODULE_IGNORE_DIRTY', + 'GIT_SUBMODULE_IGNORE_NONE', + 'GIT_SUBMODULE_IGNORE_UNSPECIFIED', + 'GIT_SUBMODULE_IGNORE_UNTRACKED', + 'GIT_SUBMODULE_STATUS_INDEX_ADDED', + 'GIT_SUBMODULE_STATUS_INDEX_DELETED', + 'GIT_SUBMODULE_STATUS_INDEX_MODIFIED', + 'GIT_SUBMODULE_STATUS_IN_CONFIG', + 'GIT_SUBMODULE_STATUS_IN_HEAD', + 'GIT_SUBMODULE_STATUS_IN_INDEX', + 'GIT_SUBMODULE_STATUS_IN_WD', + 'GIT_SUBMODULE_STATUS_WD_ADDED', + 'GIT_SUBMODULE_STATUS_WD_DELETED', + 'GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED', + 'GIT_SUBMODULE_STATUS_WD_MODIFIED', + 'GIT_SUBMODULE_STATUS_WD_UNINITIALIZED', + 'GIT_SUBMODULE_STATUS_WD_UNTRACKED', + 'GIT_SUBMODULE_STATUS_WD_WD_MODIFIED', + 'GitError', + 'Index', + 'IndexEntry', + 'InvalidSpecError', + 'Keypair', + 'KeypairFromAgent', + 'KeypairFromMemory', + 'LIBGIT2_VER', + 'LIBGIT2_VERSION', + 'LIBGIT2_VER_MAJOR', + 'LIBGIT2_VER_MINOR', + 'LIBGIT2_VER_REVISION', + 'Mailmap', + 'Note', + 'Object', + 'Odb', + 'OdbBackend', + 'OdbBackendLoose', + 'OdbBackendPack', + 'Oid', + 'PackBuilder', + 'Passthrough', + 'Patch', + 'PathLike', + 'Payload', + 'RefLogEntry', + 'Refdb', + 'RefdbBackend', + 'RefdbFsBackend', + 'Reference', + 'Remote', + 'RemoteCallbacks', + 'Repository', + 'RevSpec', + 'Settings', + 'Signature', + 'Stash', + 'StashApplyCallbacks', + 'Submodule', + 'Tag', + 'Tree', + 'TreeBuilder', + 'UserPass', + 'Username', + 'Walker', + 'Worktree', + '__version__', + 'check_error', + 'clone_repository', + 'discover_repository', + 'features', + 'ffi', + 'filter', + 'filter_register', + 'filter_unregister', + 'functools', + 'get_credentials', + 'git_clone_options', + 'git_fetch_options', + 'hash', + 'hashfile', + 'init_file_backend', + 'init_repository', + 'option', + 'reference_is_valid_name', + 'settings', + 'to_bytes', + 'to_str', + 'tree_entry_key', +] + # Features features = enums.Feature(C.git_libgit2_features()) From 7afd6949b621973cb5194c0d89bd9cf56b97fb8e Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sun, 22 Dec 2024 10:39:12 +0700 Subject: [PATCH 21/40] remove pygit2 star imports --- pygit2/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pygit2/__init__.py b/pygit2/__init__.py index e1d7655e..6d00ead4 100644 --- a/pygit2/__init__.py +++ b/pygit2/__init__.py @@ -33,7 +33,6 @@ from ._build import __version__ # Low level API -from ._pygit2 import * from ._pygit2 import ( GIT_APPLY_LOCATION_BOTH, GIT_APPLY_LOCATION_INDEX, From b2680c3a2122f5cd162acee60b7fbb10c74fbd9f Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sun, 22 Dec 2024 14:36:51 +0700 Subject: [PATCH 22/40] fix pyproject again --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 3e07c3b4..2336a934 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,3 +63,5 @@ quote-style = "single" typeCheckingMode = "strict" pythonVersion = "3.10" reportPrivateUsage = "none" +reportAttributeAccessIssue = "none" +reportUnknownMemberType = "none" From 4970a94bbbe375826ee6ffe4e28db42012e943f7 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sun, 22 Dec 2024 14:48:40 +0700 Subject: [PATCH 23/40] fix pyproject --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 2336a934..5304bca9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,7 @@ lint.ignore = [ "B010", # setattr "F401", # unused imports "ARG002", # unused arguments + "SIM105", # try-except-pass ] [tool.ruff.format] From 40f44c12c54ffe623fc414434d3488f3f97fa286 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sun, 22 Dec 2024 18:44:52 +0700 Subject: [PATCH 24/40] fix pyproject again --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 5304bca9..975516b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,3 +66,4 @@ pythonVersion = "3.10" reportPrivateUsage = "none" reportAttributeAccessIssue = "none" reportUnknownMemberType = "none" +reportUnusedFunction = "none" From e3ed43f96f1f5e2a4fdec31add8e869fffbefe1f Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sun, 22 Dec 2024 18:48:17 +0700 Subject: [PATCH 25/40] initial commit of pygit2 callbacks.py --- pygit2/callbacks.py | 75 ++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/pygit2/callbacks.py b/pygit2/callbacks.py index 5ebe475c..3ba46252 100644 --- a/pygit2/callbacks.py +++ b/pygit2/callbacks.py @@ -62,10 +62,12 @@ API. """ +from __future__ import annotations + # Standard Library from contextlib import contextmanager from functools import wraps -from typing import Optional, Union +from typing import TYPE_CHECKING, Any, Callable, Optional, Union # pygit2 from ._pygit2 import DiffFile, Oid @@ -74,6 +76,10 @@ from .ffi import C, ffi from .utils import StrArray, maybe_string, ptr_to_bytes, to_bytes +if TYPE_CHECKING: + from .remotes import Remote, TransferProgress + from .repository import Repository + # # The payload is the way to pass information from the pygit2 API, through # libgit2, to the Python callbacks. And back. @@ -81,12 +87,12 @@ class Payload: - def __init__(self, **kw): + def __init__(self, **kw: Any): for key, value in kw.items(): setattr(self, key, value) - self._stored_exception = None + self._stored_exception: BaseException | None = None - def check_error(self, error_code): + def check_error(self, error_code: int): if error_code == C.GIT_EUSER: assert self._stored_exception is not None raise self._stored_exception @@ -112,6 +118,10 @@ class RemoteCallbacks(Payload): RemoteCallbacks(certificate=certificate). """ + if TYPE_CHECKING: + repository: Callable[[str, bool], Repository] + remote: Callable[[Repository, str, str], Remote] + def __init__(self, credentials=None, certificate_check=None): super().__init__() if credentials is not None: @@ -119,7 +129,7 @@ def __init__(self, credentials=None, certificate_check=None): if certificate_check is not None: self.certificate_check = certificate_check - def sideband_progress(self, string): + def sideband_progress(self, string: str): """ Progress output callback. Override this function with your own progress reporting function @@ -158,7 +168,7 @@ def credentials( """ raise Passthrough - def certificate_check(self, certificate, valid, host): + def certificate_check(self, certificate: None, valid: bool, host: str): """ Certificate callback. Override with your own function to determine whether to accept the server's certificate. @@ -180,7 +190,7 @@ def certificate_check(self, certificate, valid, host): raise Passthrough - def transfer_progress(self, stats): + def transfer_progress(self, stats: TransferProgress): """ Transfer progress callback. Override with your own function to report transfer progress. @@ -191,7 +201,7 @@ def transfer_progress(self, stats): The progress up to now. """ - def update_tips(self, refname, old, new): + def update_tips(self, refname: str, old: Oid, new: Oid): """ Update tips callback. Override with your own function to report reference updates. @@ -208,7 +218,7 @@ def update_tips(self, refname, old, new): The reference's new value. """ - def push_update_reference(self, refname, message): + def push_update_reference(self, refname: str, message: str | None): """ Push update reference callback. Override with your own function to report the remote's acceptance or rejection of reference updates. @@ -415,9 +425,9 @@ def git_remote_callbacks(payload): # -def libgit2_callback(f): +def libgit2_callback(f: Callable[..., int]): @wraps(f) - def wrapper(*args): + def wrapper(*args: Any) -> int: data = ffi.from_handle(args[-1]) args = args[:-1] + (data,) try: @@ -436,10 +446,10 @@ def wrapper(*args): return ffi.def_extern()(wrapper) -def libgit2_callback_void(f): +def libgit2_callback_void(f: Callable[..., object]): @wraps(f) - def wrapper(*args): - data = ffi.from_handle(args[-1]) + def wrapper(*args: Any): + data: Payload = ffi.from_handle(args[-1]) args = args[:-1] + (data,) try: f(*args) @@ -457,7 +467,7 @@ def wrapper(*args): @libgit2_callback -def _certificate_check_cb(cert_i, valid, host, data): +def _certificate_check_cb(cert_i, valid: int, host, data: RemoteCallbacks): # We want to simulate what should happen if libgit2 supported pass-through # for this callback. For SSH, 'valid' is always False, because it doesn't # look at known_hosts, but we do want to let it through in order to do what @@ -479,7 +489,7 @@ def _certificate_check_cb(cert_i, valid, host, data): @libgit2_callback -def _credentials_cb(cred_out, url, username, allowed, data): +def _credentials_cb(cred_out, url, username, allowed: int, data: RemoteCallbacks): credentials = getattr(data, 'credentials', None) if not credentials: return 0 @@ -493,7 +503,7 @@ def _credentials_cb(cred_out, url, username, allowed, data): @libgit2_callback -def _push_update_reference_cb(ref, msg, data): +def _push_update_reference_cb(ref, msg, data: RemoteCallbacks): push_update_reference = getattr(data, 'push_update_reference', None) if not push_update_reference: return 0 @@ -519,7 +529,7 @@ def _remote_create_cb(remote_out, repo, name, url, data): @libgit2_callback -def _repository_create_cb(repo_out, path, bare, data): +def _repository_create_cb(repo_out, path, bare: int, data: RemoteCallbacks): repository = data.repository(ffi.string(path), bare != 0) # we no longer own the C object repository._disown() @@ -529,7 +539,7 @@ def _repository_create_cb(repo_out, path, bare, data): @libgit2_callback -def _sideband_progress_cb(string, length, data): +def _sideband_progress_cb(string, length: int, data: RemoteCallbacks): sideband_progress = getattr(data, 'sideband_progress', None) if not sideband_progress: return 0 @@ -540,7 +550,7 @@ def _sideband_progress_cb(string, length, data): @libgit2_callback -def _transfer_progress_cb(stats_ptr, data): +def _transfer_progress_cb(stats_ptr, data: RemoteCallbacks): from .remotes import TransferProgress transfer_progress = getattr(data, 'transfer_progress', None) @@ -552,7 +562,7 @@ def _transfer_progress_cb(stats_ptr, data): @libgit2_callback -def _update_tips_cb(refname, a, b, data): +def _update_tips_cb(refname, a, b, data: RemoteCallbacks): update_tips = getattr(data, 'update_tips', None) if not update_tips: return 0 @@ -569,7 +579,7 @@ def _update_tips_cb(refname, a, b, data): # -def get_credentials(fn, url, username, allowed): +def get_credentials(fn, url, username, allowed: CredentialType): """Call fn and return the credentials object.""" url_str = maybe_string(url) username_str = maybe_string(username) @@ -633,7 +643,7 @@ def get_credentials(fn, url, username, allowed): @libgit2_callback def _checkout_notify_cb( - why, path_cstr, baseline, target, workdir, data: CheckoutCallbacks + why: int, path_cstr, baseline, target, workdir, data: CheckoutCallbacks ): pypath = maybe_string(path_cstr) pybaseline = DiffFile.from_c(ptr_to_bytes(baseline)) @@ -660,8 +670,8 @@ def _checkout_progress_cb(path, completed_steps, total_steps, data: CheckoutCall def _git_checkout_options( - callbacks=None, - strategy=None, + callbacks: CheckoutCallbacks | None = None, + strategy: CheckoutStrategy | None = None, directory=None, paths=None, c_checkout_options_ptr=None, @@ -693,7 +703,7 @@ def _git_checkout_options( if paths: strarray = StrArray(paths) - refs.append(strarray) + refs.append(strarray) # type: ignore opts.paths = strarray.ptr[0] # If we want to receive any notifications, set up notify_cb in the options @@ -717,7 +727,12 @@ def _git_checkout_options( @contextmanager -def git_checkout_options(callbacks=None, strategy=None, directory=None, paths=None): +def git_checkout_options( + callbacks: CheckoutCallbacks | None = None, + strategy=None, + directory=None, + paths=None, +): yield _git_checkout_options( callbacks=callbacks, strategy=strategy, directory=directory, paths=paths ) @@ -746,7 +761,11 @@ def _stash_apply_progress_cb(progress: StashApplyProgress, data: StashApplyCallb @contextmanager def git_stash_apply_options( - callbacks=None, reinstate_index=False, strategy=None, directory=None, paths=None + callbacks: StashApplyCallbacks | None = None, + reinstate_index: bool = False, + strategy=None, + directory=None, + paths=None, ): if callbacks is None: callbacks = StashApplyCallbacks() From 35fb5e1e2a300558de7860bfa7cbf990afdec7c8 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sun, 22 Dec 2024 18:54:59 +0700 Subject: [PATCH 26/40] typing fix for __init__.py --- pygit2/__init__.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pygit2/__init__.py b/pygit2/__init__.py index 6d00ead4..778ba6cb 100644 --- a/pygit2/__init__.py +++ b/pygit2/__init__.py @@ -823,7 +823,7 @@ def init_repository( - path: typing.Union[str, bytes, PathLike, None], + path: typing.Union[str, bytes, PathLike[str], PathLike[bytes], None], bare: bool = False, flags: enums.RepositoryInitFlag = enums.RepositoryInitFlag.MKPATH, mode: typing.Union[ @@ -901,15 +901,15 @@ def init_repository( def clone_repository( - url, - path, - bare=False, - repository=None, - remote=None, - checkout_branch=None, - callbacks=None, - depth=0, -): + url: str, + path: str, + bare: bool = False, + repository: typing.Callable[[str, bool], Repository] | None = None, + remote: typing.Callable[[Repository, str, str], Remote] | None = None, + checkout_branch: str | None = None, + callbacks: RemoteCallbacks | None = None, + depth: int = 0, +) -> Repository: """ Clones a new Git repository from *url* in the given *path*. From c3b01f8e6e92fe1d4a93007a879cbcf1adf75f3e Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Tue, 24 Dec 2024 16:57:14 +0700 Subject: [PATCH 27/40] fix typing for _build.py and _run.py --- pygit2/_build.py | 2 +- pygit2/_run.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pygit2/_build.py b/pygit2/_build.py index 1e7272a9..65716021 100644 --- a/pygit2/_build.py +++ b/pygit2/_build.py @@ -48,7 +48,7 @@ def _get_libgit2_path(): # Default if os.name == 'nt': - return Path(r'%s\libgit2' % os.getenv('ProgramFiles')) + return Path(r'%s\libgit2' % os.getenv('ProgramFiles')) # noqa: SIM112 return Path('/usr/local') diff --git a/pygit2/_run.py b/pygit2/_run.py index 94f99426..cd798214 100644 --- a/pygit2/_run.py +++ b/pygit2/_run.py @@ -45,7 +45,7 @@ # C_HEADER_SRC if getattr(sys, 'frozen', False): if hasattr(sys, '_MEIPASS'): - dir_path = Path(sys._MEIPASS) + dir_path = Path(sys._MEIPASS) # type: ignore else: dir_path = Path(sys.executable).parent else: @@ -83,10 +83,10 @@ 'submodule.h', 'callbacks.h', # Bridge from libgit2 to Python ] -h_source = [] +h_source: list[str] = [] for h_file in h_files: - h_file = dir_path / 'decl' / h_file - with codecs.open(h_file, 'r', 'utf-8') as f: + h_file = dir_path / 'decl' / h_file # noqa: PLW2901 + with codecs.open(str(h_file), 'r', 'utf-8') as f: h_source.append(f.read()) C_HEADER_SRC = '\n'.join(h_source) @@ -99,7 +99,7 @@ # ffi _, libgit2_kw = get_libgit2_paths() ffi = FFI() -ffi.set_source('pygit2._libgit2', C_PREAMBLE, **libgit2_kw) +ffi.set_source('pygit2._libgit2', C_PREAMBLE, **libgit2_kw) # type: ignore ffi.cdef(C_HEADER_SRC) From 0fe1aacdf93a2d63187d8ab06cee345e3535f989 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Wed, 25 Dec 2024 17:49:30 +0700 Subject: [PATCH 28/40] fix pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 975516b1..49e097e9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,6 @@ target-version = "py310" # oldest supported Python version fix = true extend-exclude = [".cache", ".coverage", "build", "venv*"] lint.select = [ - "C", "E", "W", "F", @@ -67,3 +66,4 @@ reportPrivateUsage = "none" reportAttributeAccessIssue = "none" reportUnknownMemberType = "none" reportUnusedFunction = "none" +reportUnnecessaryIsInstance = "none" From 58b88c2d46cc4ae011cd3cb22ede1c9b2a93992c Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Wed, 25 Dec 2024 18:00:17 +0700 Subject: [PATCH 29/40] add typing for packbuilder.py --- pygit2/packbuilder.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/pygit2/packbuilder.py b/pygit2/packbuilder.py index 8fefcd89..47686d80 100644 --- a/pygit2/packbuilder.py +++ b/pygit2/packbuilder.py @@ -25,24 +25,29 @@ # Import from pygit2 + +from typing import Any + +from ._pygit2 import Oid from .errors import check_error from .ffi import C, ffi -from .utils import to_bytes +from .repository import BaseRepository +from .utils import StrOrBytesOrPathLike, buffer_to_bytes, to_bytes class PackBuilder: - def __init__(self, repo): + def __init__(self, repo: BaseRepository): cpackbuilder = ffi.new('git_packbuilder **') err = C.git_packbuilder_new(cpackbuilder, repo._repo) check_error(err) self._repo = repo - self._packbuilder = cpackbuilder[0] + self._packbuilder: Any = cpackbuilder[0] self._cpackbuilder = cpackbuilder @property def _pointer(self): - return bytes(ffi.buffer(self._packbuilder)[:]) + return bytes(buffer_to_bytes(self._packbuilder)) def __del__(self): C.git_packbuilder_free(self._packbuilder) @@ -51,29 +56,31 @@ def __len__(self): return C.git_packbuilder_object_count(self._packbuilder) @staticmethod - def __convert_object_to_oid(oid): + def __convert_object_to_oid(oid: Oid): git_oid = ffi.new('git_oid *') ffi.buffer(git_oid)[:] = oid.raw[:] return git_oid - def add(self, oid): + def add(self, oid: Oid): git_oid = self.__convert_object_to_oid(oid) err = C.git_packbuilder_insert(self._packbuilder, git_oid, ffi.NULL) check_error(err) - def add_recur(self, oid): + def add_recur(self, oid: Oid): git_oid = self.__convert_object_to_oid(oid) err = C.git_packbuilder_insert_recur(self._packbuilder, git_oid, ffi.NULL) check_error(err) - def set_threads(self, n_threads): + def set_threads(self, n_threads: int): return C.git_packbuilder_set_threads(self._packbuilder, n_threads) - def write(self, path=None): - path = ffi.NULL if path is None else to_bytes(path) - err = C.git_packbuilder_write(self._packbuilder, path, 0, ffi.NULL, ffi.NULL) + def write(self, path: StrOrBytesOrPathLike | None = None): + resolved_path = ffi.NULL if path is None else to_bytes(path) + err = C.git_packbuilder_write( + self._packbuilder, resolved_path, 0, ffi.NULL, ffi.NULL + ) check_error(err) @property - def written_objects_count(self): + def written_objects_count(self) -> int: return C.git_packbuilder_written(self._packbuilder) From d8755fb005d1b95e22ebdd593a1daeb2e4ddb8df Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Wed, 25 Dec 2024 18:00:49 +0700 Subject: [PATCH 30/40] fix typing for utils --- pygit2/utils.py | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/pygit2/utils.py b/pygit2/utils.py index fa220467..90890644 100644 --- a/pygit2/utils.py +++ b/pygit2/utils.py @@ -28,18 +28,20 @@ import contextlib import os from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast +from typing import TYPE_CHECKING, Any, Generic, TypeAlias, TypeVar, cast, overload # Import from pygit2 from .ffi import C, ffi if TYPE_CHECKING: + from _cffi_backend import _CDataBase as CData from _typeshed import SupportsLenAndGetItem _T = TypeVar('_T') +StrOrBytesOrPathLike: TypeAlias = str | bytes | os.PathLike[str] | os.PathLike[bytes] -def maybe_string(ptr: Any) -> str | None: +def maybe_string(ptr: CData | Any) -> str | None: if not ptr: return None @@ -49,20 +51,33 @@ def maybe_string(ptr: Any) -> str | None: return out -def to_bytes(s: Any, encoding: str = 'utf-8', errors: str = 'strict') -> bytes | Any: +# Cannot describe ffi.NULL, so using CData + + +@overload +def to_bytes(s: CData | None) -> CData: ... +@overload +def to_bytes(s: StrOrBytesOrPathLike) -> bytes: ... + + +def to_bytes( + s: StrOrBytesOrPathLike | CData | None, + encoding: str = 'utf-8', + errors: str = 'strict', +) -> bytes | CData: if s == ffi.NULL or s is None: return ffi.NULL - if hasattr(s, '__fspath__'): + if isinstance(s, os.PathLike): s = os.fspath(s) if isinstance(s, bytes): return s - return s.encode(encoding, errors) + return cast(str, s).encode(encoding, errors) -def to_str(s: Any) -> str: +def to_str(s: StrOrBytesOrPathLike) -> str: if hasattr(s, '__fspath__'): s = os.fspath(s) @@ -75,14 +90,18 @@ def to_str(s: Any) -> str: raise TypeError(f'unexpected type "{repr(s)}"') +def buffer_to_bytes(cdata: CData) -> bytes: + buf = ffi.buffer(cdata) + return cast(bytes, buf[:]) + + def ptr_to_bytes(ptr_cdata: Any) -> bytes: """ Convert a pointer coming from C code () to a byte buffer containing the address that the pointer refers to. """ - pp = ffi.new('void **', ptr_cdata) - return bytes(ffi.buffer(pp)[:]) # type: ignore + return buffer_to_bytes(ffi.new('void **', ptr_cdata)) @contextlib.contextmanager From 8114f2b285887b55d5f76010f92bdad82ca009cf Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Wed, 25 Dec 2024 18:02:02 +0700 Subject: [PATCH 31/40] hotfix for packbuilder.py --- pygit2/packbuilder.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pygit2/packbuilder.py b/pygit2/packbuilder.py index 47686d80..81e2dbbe 100644 --- a/pygit2/packbuilder.py +++ b/pygit2/packbuilder.py @@ -23,17 +23,18 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. +from __future__ import annotations -# Import from pygit2 - -from typing import Any +from typing import TYPE_CHECKING, Any +# Import from pygit2 from ._pygit2 import Oid from .errors import check_error from .ffi import C, ffi -from .repository import BaseRepository from .utils import StrOrBytesOrPathLike, buffer_to_bytes, to_bytes +if TYPE_CHECKING: + from .repository import BaseRepository class PackBuilder: def __init__(self, repo: BaseRepository): From 071df9d588200153c4dd8119835785c494d9a5a4 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Wed, 25 Dec 2024 18:03:16 +0700 Subject: [PATCH 32/40] fix _pygit2.pyi --- pygit2/_pygit2.pyi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pygit2/_pygit2.pyi b/pygit2/_pygit2.pyi index f745f289..c0257ca2 100644 --- a/pygit2/_pygit2.pyi +++ b/pygit2/_pygit2.pyi @@ -298,7 +298,7 @@ class Object: @overload def peel( self, target_type: Literal[None, ObjectType.ANY] - ) -> Commit | Tree | Blob: ... + ) -> Commit | Tree | Blob | Tag: ... def read_raw(self) -> bytes: ... def __eq__(self, other: object) -> bool: ... def __ge__(self, other: object) -> bool: ... @@ -693,9 +693,9 @@ class Repository: references_return_type: ReferenceFilter = ReferenceFilter.ALL, ) -> Reference: ... def reset(self, oid: _OidArg, reset_type: ResetMode) -> None: ... - def revparse(self, revspec: str) -> RevSpec: ... - def revparse_ext(self, revision: str) -> tuple[Object, Reference]: ... - def revparse_single(self, revision: str) -> Object: ... + def revparse(self, revspec: str | bytes) -> RevSpec: ... + def revparse_ext(self, revision: str | bytes) -> tuple[Object, Reference]: ... + def revparse_single(self, revision: str | bytes) -> Object: ... def set_odb(self, odb: Odb) -> None: ... def set_refdb(self, refdb: Refdb) -> None: ... def status( From 9a10a41cd9feb2549c2397e0af04b92d4d134d1d Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Wed, 25 Dec 2024 18:03:40 +0700 Subject: [PATCH 33/40] initial stub for repository.py --- pygit2/repository.py | 301 +++++++++++++++++++++++++++---------------- 1 file changed, 188 insertions(+), 113 deletions(-) diff --git a/pygit2/repository.py b/pygit2/repository.py index fb2d7038..cc3799f4 100644 --- a/pygit2/repository.py +++ b/pygit2/repository.py @@ -23,6 +23,8 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. +from __future__ import annotations + import tarfile import typing from io import BytesIO @@ -36,6 +38,7 @@ Blob, Commit, InvalidSpecError, + Object, Oid, Reference, Signature, @@ -47,7 +50,12 @@ from ._pygit2 import Repository as _Repository from .blame import Blame from .branches import Branches -from .callbacks import git_checkout_options, git_stash_apply_options +from .callbacks import ( + CheckoutCallbacks, + StashApplyCallbacks, + git_checkout_options, + git_stash_apply_options, +) from .config import Config from .enums import ( AttrCheck, @@ -73,9 +81,11 @@ from .submodules import SubmoduleCollection from .utils import StrArray, to_bytes +T = typing.TypeVar('T') + class BaseRepository(_Repository): - def __init__(self, *args, **kwargs): + def __init__(self, *args: typing.Any, **kwargs: typing.Any): super().__init__(*args, **kwargs) self._common_init() @@ -92,22 +102,28 @@ def _common_init(self): self._repo = repo_cptr[0] # Backwards compatible ODB access - def read(self, *args, **kwargs): + # def read(self, *args, **kwargs): + def read(self, oid: Oid | str) -> tuple[int, int, bytes]: """read(oid) -> type, data, size Read raw object data from the repository. """ - return self.odb.read(*args, **kwargs) + return self.odb.read(oid) - def write(self, *args, **kwargs): + def write(self, type: int, data: bytes) -> Oid: """write(type, data) -> Oid Write raw object data into the repository. First arg is the object type, the second one a buffer with data. Return the Oid of the created object.""" - return self.odb.write(*args, **kwargs) + return self.odb.write(type, data) - def pack(self, path=None, pack_delegate=None, n_threads=None): + def pack( + self, + path: str | bytes | PathLike[str] | PathLike[bytes] | None = None, + pack_delegate: typing.Callable[[PackBuilder], object] | None = None, + n_threads: int | None = None, + ) -> int: """Pack the objects in the odb chosen by the pack_delegate function and write `.pack` and `.idx` files for them. @@ -125,7 +141,7 @@ def pack(self, path=None, pack_delegate=None, n_threads=None): The number of threads the `PackBuilder` will spawn. If set to 0, libgit2 will autodetect the number of CPUs. """ - def pack_all_objects(pack_builder): + def pack_all_objects(pack_builder: PackBuilder) -> None: for obj in self.odb: pack_builder.add(obj) @@ -141,10 +157,10 @@ def pack_all_objects(pack_builder): def hashfile( self, - path: str, + path: str | bytes | PathLike[str] | PathLike[bytes], object_type: ObjectType = ObjectType.BLOB, - as_path: typing.Optional[str] = None, - ): + as_path: typing.Optional[str | bytes | PathLike[str] | PathLike[bytes]] = None, + ) -> Oid: """Calculate the hash of a file using repository filtering rules. If you simply want to calculate the hash of a file on disk with no filters, @@ -185,8 +201,7 @@ def hashfile( ) check_error(err) - oid = Oid(raw=bytes(ffi.buffer(c_oid.id)[:])) - return oid + return Oid(raw=bytes(ffi.buffer(c_oid.id)[:])) def __iter__(self): return iter(self.odb) @@ -194,27 +209,30 @@ def __iter__(self): # # Mapping interface # - def get(self, key, default=None): + def get(self, key: Oid | str, default: T = None) -> Object | T: value = self.git_object_lookup_prefix(key) return value if (value is not None) else default - def __getitem__(self, key): + def __getitem__(self, key: Object | Oid | str) -> Object: + # Maybe either returns itself or lookup???? + if isinstance(key, Object): + key = key.id value = self.git_object_lookup_prefix(key) if value is None: raise KeyError(key) return value - def __contains__(self, key): + def __contains__(self, key: Oid | str) -> bool: return self.git_object_lookup_prefix(key) is not None - def __repr__(self): + def __repr__(self) -> str: return f'pygit2.Repository({repr(self.path)})' # # Configuration # @property - def config(self): + def config(self) -> Config: """The configuration file for this repository. If a the configuration hasn't been set yet, the default config for @@ -228,7 +246,7 @@ def config(self): return Config.from_c(self, cconfig[0]) @property - def config_snapshot(self): + def config_snapshot(self) -> Config: """A snapshot for this repositiory's configuration This allows reads over multiple values to use the same version @@ -243,7 +261,13 @@ def config_snapshot(self): # # References # - def create_reference(self, name, target, force=False, message=None): + def create_reference( + self, + name: str, + target: Oid | str, + force: bool = False, + message: str | None = None, + ) -> Reference: """Create a new reference "name" which points to an object or to another reference. @@ -265,7 +289,7 @@ def create_reference(self, name, target, force=False, message=None): repo.create_reference('refs/tags/foo', 'refs/heads/master') repo.create_reference('refs/tags/foo', 'bbb78a9cec580') """ - direct = type(target) is Oid or ( + direct = isinstance(target, Oid) or ( all(c in hexdigits for c in target) and GIT_OID_MINPREFIXLEN <= len(target) <= GIT_OID_HEXSZ ) @@ -275,15 +299,15 @@ def create_reference(self, name, target, force=False, message=None): return self.create_reference_symbolic(name, target, force, message=message) - def listall_references(self) -> typing.List[str]: + def listall_references(self) -> list[str]: """Return a list with all the references in the repository.""" return [x.name for x in self.references.iterator()] - def listall_reference_objects(self) -> typing.List[Reference]: + def listall_reference_objects(self) -> list[Reference]: """Return a list with all the reference objects in the repository.""" return list(self.references.iterator()) - def resolve_refish(self, refish): + def resolve_refish(self, refish: str) -> tuple[Commit, Reference | None]: """Convert a reference-like short name "ref-ish" to a valid (commit, reference) pair. @@ -301,7 +325,7 @@ def resolve_refish(self, refish): reference = self.lookup_reference_dwim(refish) except (KeyError, InvalidSpecError): reference = None - commit = self.revparse_single(refish) + commit: Commit = self.revparse_single(refish) else: commit = reference.peel(Commit) @@ -311,21 +335,36 @@ def resolve_refish(self, refish): # Checkout # - def checkout_head(self, **kwargs): + def checkout_head( + self, + strategy: CheckoutStrategy = CheckoutStrategy.SAFE + | CheckoutStrategy.RECREATE_MISSING, + directory: str | None = None, + paths: list[str] | None = None, + callbacks: CheckoutCallbacks | None = None, + ): """Checkout HEAD For arguments, see Repository.checkout(). """ - with git_checkout_options(**kwargs) as payload: + with git_checkout_options(callbacks, strategy, directory, paths) as payload: err = C.git_checkout_head(self._repo, payload.checkout_options) payload.check_error(err) - def checkout_index(self, index=None, **kwargs): + def checkout_index( + self, + index: Index | None = None, + strategy: CheckoutStrategy = CheckoutStrategy.SAFE + | CheckoutStrategy.RECREATE_MISSING, + directory: str | None = None, + paths: list[str] | None = None, + callbacks: CheckoutCallbacks | None = None, + ) -> None: """Checkout the given index or the repository's index For arguments, see Repository.checkout(). """ - with git_checkout_options(**kwargs) as payload: + with git_checkout_options(callbacks, strategy, directory, paths) as payload: err = C.git_checkout_index( self._repo, index._index if index else ffi.NULL, @@ -333,18 +372,34 @@ def checkout_index(self, index=None, **kwargs): ) payload.check_error(err) - def checkout_tree(self, treeish, **kwargs): + def checkout_tree( + self, + treeish: typing.Any, + strategy: CheckoutStrategy = CheckoutStrategy.SAFE + | CheckoutStrategy.RECREATE_MISSING, + directory: str | None = None, + paths: list[str] | None = None, + callbacks: CheckoutCallbacks | None = None, + ) -> None: """Checkout the given treeish For arguments, see Repository.checkout(). """ - with git_checkout_options(**kwargs) as payload: + with git_checkout_options(callbacks, strategy, directory, paths) as payload: cptr = ffi.new('git_object **') ffi.buffer(cptr)[:] = treeish._pointer[:] err = C.git_checkout_tree(self._repo, cptr[0], payload.checkout_options) payload.check_error(err) - def checkout(self, refname=None, **kwargs): + def checkout( + self, + refname: str | Reference | None = None, + strategy: CheckoutStrategy = CheckoutStrategy.SAFE + | CheckoutStrategy.RECREATE_MISSING, + directory: str | None = None, + paths: list[str] | None = None, + callbacks: CheckoutCallbacks | None = None, + ): """ Checkout the given reference using the given strategy, and update the HEAD. @@ -389,11 +444,15 @@ def checkout(self, refname=None, **kwargs): # Case 1: Checkout index if refname is None: - return self.checkout_index(**kwargs) + return self.checkout_index( + strategy=strategy, directory=directory, paths=paths, callbacks=callbacks + ) # Case 2: Checkout head if refname == 'HEAD': - return self.checkout_head(**kwargs) + return self.checkout_head( + strategy=strategy, directory=directory, paths=paths, callbacks=callbacks + ) # Case 3: Reference if isinstance(refname, Reference): @@ -404,15 +463,21 @@ def checkout(self, refname=None, **kwargs): oid = reference.resolve().target treeish = self[oid] - self.checkout_tree(treeish, **kwargs) + self.checkout_tree( + treeish, + strategy=strategy, + directory=directory, + paths=paths, + callbacks=callbacks, + ) - if 'paths' not in kwargs: + if paths is None: self.set_head(refname) # # Setting HEAD # - def set_head(self, target): + def set_head(self, target: str | Oid) -> None: """ Set HEAD to point to the given target. @@ -436,34 +501,34 @@ def set_head(self, target): # # Diff # - def __whatever_to_tree_or_blob(self, obj): + def __whatever_to_tree_or_blob(self, obj: str | bytes | Oid | None): if obj is None: return None # If it's a string, then it has to be valid revspec - if isinstance(obj, (str, bytes)): - obj = self.revparse_single(obj) - elif isinstance(obj, Oid): - obj = self[obj] + if isinstance(obj, (str, bytes)): # noqa: SIM108 + robj = self.revparse_single(obj) + else: + robj = self[obj] # First we try to get to a blob try: - obj = obj.peel(Blob) + robj = robj.peel(Blob) except Exception: # And if that failed, try to get a tree, raising a type # error if that still doesn't work try: - obj = obj.peel(Tree) + robj = robj.peel(Tree) except Exception: - raise TypeError(f'unexpected "{type(obj)}"') + raise TypeError(f'unexpected "{type(obj)}"') from None - return obj + return robj def diff( self, - a=None, - b=None, - cached=False, + a: str | Reference | None = None, + b: str | Reference | None = None, + cached: bool = False, flags: DiffOption = DiffOption.NORMAL, context_lines: int = 3, interhunk_lines: int = 0, @@ -525,30 +590,34 @@ def diff( API (Tree.diff_to_tree()) directly. """ - a = self.__whatever_to_tree_or_blob(a) - b = self.__whatever_to_tree_or_blob(b) - - opt_keys = ['flags', 'context_lines', 'interhunk_lines'] - opt_values = [int(flags), context_lines, interhunk_lines] + resolved_a = self.__whatever_to_tree_or_blob(a) + resolved_b = self.__whatever_to_tree_or_blob(b) # Case 1: Diff tree to tree - if isinstance(a, Tree) and isinstance(b, Tree): - return a.diff_to_tree(b, **dict(zip(opt_keys, opt_values, strict=False))) + if isinstance(resolved_a, Tree) and isinstance(resolved_b, Tree): + return resolved_a.diff_to_tree( + resolved_b, + flags=flags, + context_lines=context_lines, + interhunk_lines=interhunk_lines, + ) # Case 2: Index to workdir - elif a is None and b is None: - return self.index.diff_to_workdir(*opt_values) + elif resolved_a is None and resolved_b is None: + return self.index.diff_to_workdir(flags, context_lines, interhunk_lines) # Case 3: Diff tree to index or workdir - elif isinstance(a, Tree) and b is None: + elif isinstance(resolved_a, Tree) and resolved_b is None: if cached: - return a.diff_to_index(self.index, *opt_values) + return resolved_a.diff_to_index( + self.index, flags, context_lines, interhunk_lines + ) else: - return a.diff_to_workdir(*opt_values) + return resolved_a.diff_to_workdir(flags, context_lines, interhunk_lines) # Case 4: Diff blob to blob - if isinstance(a, Blob) and isinstance(b, Blob): - return a.diff(b) + if isinstance(resolved_a, Blob) and isinstance(resolved_b, Blob): + return resolved_a.diff(resolved_b) raise ValueError('Only blobs and treeish can be diffed') @@ -563,7 +632,7 @@ def state(self) -> RepositoryState: return RepositoryState(cstate) except ValueError: # Some value not in the IntEnum - newer libgit2 version? - return cstate + raise def state_cleanup(self): """Remove all the metadata associated with an ongoing command like @@ -577,13 +646,13 @@ def state_cleanup(self): # def blame( self, - path, + path: str, flags: BlameFlag = BlameFlag.NORMAL, - min_match_characters=None, - newest_commit=None, - oldest_commit=None, - min_line=None, - max_line=None, + min_match_characters: int | None = None, + newest_commit: Oid | str | None = None, + oldest_commit: Oid | str | None = None, + min_line: int | None = None, + max_line: int | None = None, ): """ Return a Blame object for a single file. @@ -700,13 +769,11 @@ def merge_file_from_index( """ cmergeresult = ffi.new('git_merge_file_result *') - cancestor, ancestor_str_ref = ( + cancestor, _ = ( ancestor._to_c() if ancestor is not None else (ffi.NULL, ffi.NULL) ) - cours, ours_str_ref = ours._to_c() if ours is not None else (ffi.NULL, ffi.NULL) - ctheirs, theirs_str_ref = ( - theirs._to_c() if theirs is not None else (ffi.NULL, ffi.NULL) - ) + cours, _ = ours._to_c() if ours is not None else (ffi.NULL, ffi.NULL) + ctheirs, _ = theirs._to_c() if theirs is not None else (ffi.NULL, ffi.NULL) err = C.git_merge_file_from_index( cmergeresult, self._repo, cancestor, cours, ctheirs, ffi.NULL @@ -722,9 +789,9 @@ def merge_commits( self, ours: typing.Union[str, Oid, Commit], theirs: typing.Union[str, Oid, Commit], - favor=MergeFavor.NORMAL, - flags=MergeFlag.FIND_RENAMES, - file_flags=MergeFileFlag.DEFAULT, + favor: MergeFavor = MergeFavor.NORMAL, + flags: MergeFlag = MergeFlag.FIND_RENAMES, + file_flags: MergeFileFlag = MergeFileFlag.DEFAULT, ) -> Index: """ Merge two arbitrary commits. @@ -756,18 +823,20 @@ def merge_commits( theirs_ptr = ffi.new('git_commit **') cindex = ffi.new('git_index **') + object_ours, object_theirs = ours, theirs + if isinstance(ours, (str, Oid)): - ours = self[ours] + object_ours = self[ours] if isinstance(theirs, (str, Oid)): - theirs = self[theirs] + object_theirs = self[theirs] - ours = ours.peel(Commit) - theirs = theirs.peel(Commit) + cours = object_ours.peel(Commit) # type: ignore + ctheirs = object_theirs.peel(Commit) # type: ignore opts = self._merge_options(favor, flags, file_flags) - ffi.buffer(ours_ptr)[:] = ours._pointer[:] - ffi.buffer(theirs_ptr)[:] = theirs._pointer[:] + ffi.buffer(ours_ptr)[:] = cours._pointer[:] + ffi.buffer(theirs_ptr)[:] = ctheirs._pointer[:] err = C.git_merge_commits(cindex, self._repo, ours_ptr[0], theirs_ptr[0], opts) check_error(err) @@ -779,10 +848,10 @@ def merge_trees( ancestor: typing.Union[str, Oid, Tree], ours: typing.Union[str, Oid, Tree], theirs: typing.Union[str, Oid, Tree], - favor=MergeFavor.NORMAL, - flags=MergeFlag.FIND_RENAMES, - file_flags=MergeFileFlag.DEFAULT, - ): + favor: MergeFavor = MergeFavor.NORMAL, + flags: MergeFlag = MergeFlag.FIND_RENAMES, + file_flags: MergeFileFlag = MergeFileFlag.DEFAULT, + ) -> Index: """ Merge two trees. @@ -815,15 +884,15 @@ def merge_trees( cindex = ffi.new('git_index **') if isinstance(ancestor, (str, Oid)): - ancestor = self[ancestor] + object_ancestor = self[ancestor] if isinstance(ours, (str, Oid)): - ours = self[ours] + object_ours = self[ours] if isinstance(theirs, (str, Oid)): - theirs = self[theirs] + object_theirs = self[theirs] - ancestor = ancestor.peel(Tree) - ours = ours.peel(Tree) - theirs = theirs.peel(Tree) + ancestor = object_ancestor.peel(Tree) # type: ignore + ours = object_ours.peel(Tree) # type: ignore + theirs = object_theirs.peel(Tree) # type: ignore opts = self._merge_options(favor, flags, file_flags) @@ -841,10 +910,10 @@ def merge_trees( def merge( self, id: typing.Union[Oid, str], - favor=MergeFavor.NORMAL, - flags=MergeFlag.FIND_RENAMES, - file_flags=MergeFileFlag.DEFAULT, - ): + favor: MergeFavor = MergeFavor.NORMAL, + flags: MergeFlag = MergeFlag.FIND_RENAMES, + file_flags: MergeFileFlag = MergeFileFlag.DEFAULT, + ) -> None: """ Merges the given id into HEAD. @@ -906,7 +975,7 @@ def raw_message(self) -> bytes: if err == C.GIT_ENOTFOUND: return b'' check_error(err) - return ffi.string(buf.ptr) + return ffi.string(buf.ptr) # type: ignore finally: C.git_buf_dispose(buf) @@ -941,16 +1010,16 @@ def remove_message(self): # def describe( self, - committish=None, - max_candidates_tags=None, + committish: str | Reference | Commit | None = None, + max_candidates_tags: int | None = None, describe_strategy: DescribeStrategy = DescribeStrategy.DEFAULT, - pattern=None, - only_follow_first_parent=None, - show_commit_oid_as_fallback=None, - abbreviated_size=None, - always_use_long_format=None, - dirty_suffix=None, - ): + pattern: str | None = None, + only_follow_first_parent: bool | None = None, + show_commit_oid_as_fallback: bool | None = None, + abbreviated_size: int | None = None, + always_use_long_format: bool | None = None, + dirty_suffix: str | None = None, + ) -> str: """ Describe a commit-ish or the current working tree. @@ -1076,7 +1145,7 @@ def stash( include_ignored: bool = False, keep_all: bool = False, paths: typing.Optional[typing.List[str]] = None, - ): + ) -> Oid: """ Save changes to the working directory to the stash. @@ -1140,7 +1209,13 @@ def stash( return Oid(raw=bytes(ffi.buffer(coid)[:])) - def stash_apply(self, index=0, **kwargs): + def stash_apply( + self, + index: int = 0, + strategy: CheckoutStrategy | None = None, + reinstate_index: bool = False, + callbacks: StashApplyCallbacks | None = None, + ) -> None: """ Apply a stashed state in the stash list to the working directory. @@ -1174,11 +1249,11 @@ def stash_apply(self, index=0, **kwargs): >>> repo.stash(repo.default_signature(), 'WIP: stashing') >>> repo.stash_apply(strategy=CheckoutStrategy.ALLOW_CONFLICTS) """ - with git_stash_apply_options(**kwargs) as payload: + with git_stash_apply_options(callbacks, reinstate_index, strategy) as payload: err = C.git_stash_apply(self._repo, index, payload.stash_apply_options) payload.check_error(err) - def stash_drop(self, index=0): + def stash_drop(self, index: int = 0) -> None: """ Remove a stashed state from the stash list. @@ -1616,7 +1691,7 @@ def __init__( super().__init__() @classmethod - def _from_c(cls, ptr, owned): + def _from_c(cls, ptr, owned: bool) -> Repository: cptr = ffi.new('git_repository **') cptr[0] = ptr repo = cls.__new__(cls) From 5f2d9aebc2b542a0e695974de00aeca96d2dfa90 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Sun, 29 Dec 2024 12:45:43 +0700 Subject: [PATCH 34/40] add typing for branches.py --- pygit2/branches.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pygit2/branches.py b/pygit2/branches.py index 21d887ad..4d637da5 100644 --- a/pygit2/branches.py +++ b/pygit2/branches.py @@ -27,7 +27,7 @@ from typing import TYPE_CHECKING -from ._pygit2 import Commit, Oid +from ._pygit2 import Branch, Commit, Oid, Reference from .enums import BranchType, ReferenceType # Need BaseRepository for type hints, but don't let it cause a circular dependency @@ -37,7 +37,10 @@ class Branches: def __init__( - self, repository: BaseRepository, flag: BranchType = BranchType.ALL, commit=None + self, + repository: BaseRepository, + flag: BranchType = BranchType.ALL, + commit: Commit | Oid | str | None = None, ): self._repository = repository self._flag = flag @@ -76,13 +79,13 @@ def __iter__(self): if self._commit is None or self.get(branch_name) is not None: yield branch_name - def create(self, name: str, commit, force=False): + def create(self, name: str, commit: Commit, force: bool = False): return self._repository.create_branch(name, commit, force) def delete(self, name: str): self[name].delete() - def _valid(self, branch): + def _valid(self, branch: Branch | Reference): if branch.type == ReferenceType.SYMBOLIC: branch = branch.resolve() @@ -92,9 +95,9 @@ def _valid(self, branch): or self._repository.descendant_of(branch.target, self._commit) ) - def with_commit(self, commit): + def with_commit(self, commit: Commit | Oid | str | None): assert self._commit is None return Branches(self._repository, self._flag, commit) - def __contains__(self, name): + def __contains__(self, name: str): return self.get(name) is not None From 720881ec94318aa993a1ba52fd5d332d98ce0bdf Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Mon, 30 Dec 2024 11:42:19 +0700 Subject: [PATCH 35/40] add typing to blob.py and fix _pygit2.pyi --- pygit2/_pygit2.pyi | 15 ++++++++++++++- pygit2/blob.py | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/pygit2/_pygit2.pyi b/pygit2/_pygit2.pyi index c0257ca2..50b84982 100644 --- a/pygit2/_pygit2.pyi +++ b/pygit2/_pygit2.pyi @@ -1,4 +1,6 @@ -from io import IOBase +import queue +import threading +from io import DEFAULT_BUFFER_SIZE, IOBase from typing import Any, Callable, Iterator, Literal, Optional, TypeAlias, overload from pygit2.filter import Filter @@ -6,6 +8,7 @@ from pygit2.filter import Filter from . import Index from .enums import ( ApplyLocation, + BlobFilter, BranchType, DeltaStatus, DiffFind, @@ -363,6 +366,16 @@ class Blob(Object): old_as_path: str = ..., buffer_as_path: str = ..., ) -> Patch: ... + def _write_to_queue( + self, + queue: queue.Queue[bytes | None], + closed: threading.Event, + chunk_size: int = DEFAULT_BUFFER_SIZE, + *, + as_path: str | None = None, + flags: BlobFilter = BlobFilter.CHECK_FOR_BINARY, + commit_id: Oid | None = None, + ) -> None: ... class Branch(Reference): branch_name: str diff --git a/pygit2/blob.py b/pygit2/blob.py index 19e3f3c4..144f2b79 100644 --- a/pygit2/blob.py +++ b/pygit2/blob.py @@ -1,13 +1,19 @@ +from __future__ import annotations + import io import threading import time from contextlib import AbstractContextManager from queue import Queue -from typing import Optional +from types import TracebackType +from typing import TYPE_CHECKING, Any, Optional, overload from ._pygit2 import Blob, Oid from .enums import BlobFilter +if TYPE_CHECKING: + from _typeshed import WriteableBuffer + class _BlobIO(io.RawIOBase): """Low-level wrapper for streaming blob content. @@ -26,7 +32,7 @@ def __init__( ): super().__init__() self._blob = blob - self._queue = Queue(maxsize=1) + self._queue: Queue[bytes | None] | None = Queue(maxsize=1) self._ready = threading.Event() self._writer_closed = threading.Event() self._chunk: Optional[bytes] = None @@ -42,10 +48,15 @@ def __init__( ) self._thread.start() - def __exit__(self, exc_type, exc_value, traceback): + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: self.close() - def isatty(): + def isatty(self): return False def readable(self): @@ -57,7 +68,14 @@ def writable(self): def seekable(self): return False - def readinto(self, b, /): + # workaround for type checking + if TYPE_CHECKING: + @overload + def readinto(self, b: WriteableBuffer, /) -> int: ... # type: ignore + + def readinto(self, b: Any, /) -> int: + if not self._queue: + raise RuntimeError('Blob I/O is closed') try: while self._chunk is None: self._ready.wait() @@ -96,7 +114,7 @@ def close(self): self._queue = None -class BlobIO(io.BufferedReader, AbstractContextManager): +class BlobIO(io.BufferedReader, AbstractContextManager['BlobIO']): """Read-only wrapper for streaming blob content. Supports reading both raw and filtered blob content. @@ -147,7 +165,12 @@ def __init__( raw = _BlobIO(blob, as_path=as_path, flags=flags, commit_id=commit_id) super().__init__(raw) - def __exit__(self, exc_type, exc_value, traceback): + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: self.close() From 0e55fb33f11a9217f024ef1b7174d6b26c1789e2 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Mon, 30 Dec 2024 20:24:32 +0700 Subject: [PATCH 36/40] add typing for blame.py and add _ctyping --- pygit2/_ctyping.py | 1 + pygit2/_ctyping.pyi | 27 +++++++++++++++++++++++++++ pygit2/blame.py | 44 +++++++++++++++++++++++++------------------- 3 files changed, 53 insertions(+), 19 deletions(-) create mode 100644 pygit2/_ctyping.py create mode 100644 pygit2/_ctyping.pyi diff --git a/pygit2/_ctyping.py b/pygit2/_ctyping.py new file mode 100644 index 00000000..c5ca357e --- /dev/null +++ b/pygit2/_ctyping.py @@ -0,0 +1 @@ +# placeholder for pyright diff --git a/pygit2/_ctyping.pyi b/pygit2/_ctyping.pyi new file mode 100644 index 00000000..f33e2044 --- /dev/null +++ b/pygit2/_ctyping.pyi @@ -0,0 +1,27 @@ +from _cffi_backend import _CDataBase + +class CData(_CDataBase): ... # type: ignore + +class _CSignatureTime(CData): + time: int + offset: int + +class _CSignature(CData): + name: CData + email: CData + when: _CSignatureTime + +class _COid(CData): + id: CData + +class _CHunk(CData): + boundary: CData + final_commit_id: _COid + final_signature: _CSignature + final_start_line_number: int + lines_in_hunk: int + orig_commit_id: _COid + orig_path: str + orig_signature: _CSignature + orig_start_line_number: int + diff --git a/pygit2/blame.py b/pygit2/blame.py index 8a156362..4ae36e98 100644 --- a/pygit2/blame.py +++ b/pygit2/blame.py @@ -23,19 +23,29 @@ # the Free Software Foundation, 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301, USA. +from __future__ import annotations + +from typing import TYPE_CHECKING, cast + # Import from pygit2 from ._pygit2 import Oid, Signature from .ffi import C, ffi -from .utils import GenericIterator +from .utils import GenericIterator, buffer_to_bytes, maybe_string + +if TYPE_CHECKING: + from _cffi_backend import _CDataBase as CData + from ._ctyping import _CHunk, _CSignature + from .repository import BaseRepository -def wrap_signature(csig): + +def wrap_signature(csig: _CSignature): if not csig: return None return Signature( - ffi.string(csig.name).decode('utf-8'), - ffi.string(csig.email).decode('utf-8'), + cast(str, maybe_string(csig.name)), + cast(str, maybe_string(csig.email)), csig.when.time, csig.when.offset, 'utf-8', @@ -43,8 +53,12 @@ def wrap_signature(csig): class BlameHunk: + if TYPE_CHECKING: + _blame: Blame + _hunk: _CHunk + @classmethod - def _from_c(cls, blame, ptr): + def _from_c(cls, blame: Blame, ptr: _CHunk): hunk = cls.__new__(cls) hunk._blame = blame hunk._hunk = ptr @@ -73,9 +87,7 @@ def final_committer(self): @property def final_commit_id(self): - return Oid( - raw=bytes(ffi.buffer(ffi.addressof(self._hunk, 'final_commit_id'))[:]) - ) + return Oid(raw=buffer_to_bytes(ffi.addressof(self._hunk, 'final_commit_id'))) @property def orig_start_line_number(self): @@ -89,23 +101,17 @@ def orig_committer(self): @property def orig_commit_id(self): - return Oid( - raw=bytes(ffi.buffer(ffi.addressof(self._hunk, 'orig_commit_id'))[:]) - ) + return Oid(raw=buffer_to_bytes(ffi.addressof(self._hunk, 'orig_commit_id'))) @property def orig_path(self): """Original path""" - path = self._hunk.orig_path - if not path: - return None - - return ffi.string(path).decode('utf-8') + return maybe_string(self._hunk.orig_path) class Blame: @classmethod - def _from_c(cls, repo, ptr): + def _from_c(cls, repo: BaseRepository, ptr: CData): blame = cls.__new__(cls) blame._repo = repo blame._blame = ptr @@ -117,14 +123,14 @@ def __del__(self): def __len__(self): return C.git_blame_get_hunk_count(self._blame) - def __getitem__(self, index): + def __getitem__(self, index: int): chunk = C.git_blame_get_hunk_byindex(self._blame, index) if not chunk: raise IndexError return BlameHunk._from_c(self, chunk) - def for_line(self, line_no): + def for_line(self, line_no: int) -> BlameHunk: """ Returns the object for a given line given its number in the current Blame. From 5dca60a00ec6690f278922f37afec82af9f3434c Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Mon, 30 Dec 2024 20:38:38 +0700 Subject: [PATCH 37/40] change pathtype name to StrOrBytesPath --- pygit2/packbuilder.py | 4 ++-- pygit2/utils.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pygit2/packbuilder.py b/pygit2/packbuilder.py index 81e2dbbe..a4bae3a0 100644 --- a/pygit2/packbuilder.py +++ b/pygit2/packbuilder.py @@ -31,7 +31,7 @@ from ._pygit2 import Oid from .errors import check_error from .ffi import C, ffi -from .utils import StrOrBytesOrPathLike, buffer_to_bytes, to_bytes +from .utils import StrOrBytesPath, buffer_to_bytes, to_bytes if TYPE_CHECKING: from .repository import BaseRepository @@ -75,7 +75,7 @@ def add_recur(self, oid: Oid): def set_threads(self, n_threads: int): return C.git_packbuilder_set_threads(self._packbuilder, n_threads) - def write(self, path: StrOrBytesOrPathLike | None = None): + def write(self, path: StrOrBytesPath | None = None): resolved_path = ffi.NULL if path is None else to_bytes(path) err = C.git_packbuilder_write( self._packbuilder, resolved_path, 0, ffi.NULL, ffi.NULL diff --git a/pygit2/utils.py b/pygit2/utils.py index d2f13e55..61dcd549 100644 --- a/pygit2/utils.py +++ b/pygit2/utils.py @@ -38,7 +38,7 @@ from _typeshed import SupportsLenAndGetItem _T = TypeVar('_T') -StrOrBytesOrPathLike: TypeAlias = str | bytes | os.PathLike[str] | os.PathLike[bytes] +StrOrBytesPath: TypeAlias = str | bytes | os.PathLike[str] | os.PathLike[bytes] def maybe_string(ptr: CData | Any) -> str | None: @@ -57,11 +57,11 @@ def maybe_string(ptr: CData | Any) -> str | None: @overload def to_bytes(s: CData | None) -> CData: ... @overload -def to_bytes(s: StrOrBytesOrPathLike) -> bytes: ... +def to_bytes(s: StrOrBytesPath) -> bytes: ... def to_bytes( - s: StrOrBytesOrPathLike | CData | None, + s: StrOrBytesPath | CData | None, encoding: str = 'utf-8', errors: str = 'strict', ) -> bytes | CData: @@ -77,7 +77,7 @@ def to_bytes( return cast(str, s).encode(encoding, errors) -def to_str(s: StrOrBytesOrPathLike) -> str: +def to_str(s: StrOrBytesPath) -> str: if hasattr(s, '__fspath__'): s = os.fspath(s) From 599f2b7ca718024461e1907f2562da17f79dceb1 Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Mon, 30 Dec 2024 20:53:52 +0700 Subject: [PATCH 38/40] fix _ctyping --- pygit2/_ctyping.pyi | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pygit2/_ctyping.pyi b/pygit2/_ctyping.pyi index f33e2044..9697ae4e 100644 --- a/pygit2/_ctyping.pyi +++ b/pygit2/_ctyping.pyi @@ -21,7 +21,15 @@ class _CHunk(CData): final_start_line_number: int lines_in_hunk: int orig_commit_id: _COid - orig_path: str + orig_path: _CDataBase orig_signature: _CSignature orig_start_line_number: int +class _CConfigEntry(CData): + backend_type: _CDataBase + free: _CDataBase + include_depth: int + level: int + name: _CDataBase + origin_path: _CDataBase + value: _CDataBase From d3be17af49c2f9bbb2c07728389676cfdd620e8b Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Mon, 30 Dec 2024 20:55:02 +0700 Subject: [PATCH 39/40] fix _ctyping again --- pygit2/_ctyping.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pygit2/_ctyping.pyi b/pygit2/_ctyping.pyi index 9697ae4e..2be1411f 100644 --- a/pygit2/_ctyping.pyi +++ b/pygit2/_ctyping.pyi @@ -7,12 +7,12 @@ class _CSignatureTime(CData): offset: int class _CSignature(CData): - name: CData - email: CData + name: _CDataBase + email: _CDataBase when: _CSignatureTime class _COid(CData): - id: CData + id: _CDataBase class _CHunk(CData): boundary: CData From dddd720f5706b72e75223d4225a6cf75d115bc9f Mon Sep 17 00:00:00 2001 From: DinhHuy2010 Date: Mon, 30 Dec 2024 21:16:57 +0700 Subject: [PATCH 40/40] add maybe_bytes --- pygit2/utils.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pygit2/utils.py b/pygit2/utils.py index 61dcd549..fb261bcf 100644 --- a/pygit2/utils.py +++ b/pygit2/utils.py @@ -41,11 +41,16 @@ StrOrBytesPath: TypeAlias = str | bytes | os.PathLike[str] | os.PathLike[bytes] -def maybe_string(ptr: CData | Any) -> str | None: +def maybe_bytes(ptr: CData | Any) -> bytes | None: if not ptr: return None out = ffi.string(ptr) + return cast(bytes, out) + + +def maybe_string(ptr: CData | Any) -> str | None: + out = maybe_bytes(ptr) if isinstance(out, bytes): out = out.decode('utf8') return out