Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pygit2: bump to 1.14.0 #312

Merged
merged 7 commits into from
Jan 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-20.04, windows-latest, macos-latest]
pyv: ['3.8', '3.9', '3.10', '3.11']
pyv: ['3.9', '3.10', '3.11', '3.12']

steps:
- name: Check out the repository
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Request features on the `Issue Tracker`_.
How to set up your development environment
------------------------------------------

You need Python 3.8+ and the following tools:
You need Python 3.9+ and the following tools:

- Nox_

Expand Down
2 changes: 1 addition & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
locations = "src", "tests"


@nox.session(python=["3.8", "3.9", "3.10", "3.11"])
@nox.session(python=["3.9", "3.10", "3.11", "3.12"])
def tests(session: nox.Session) -> None:
session.install(".[tests]")
session.run(
Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ license = {text = "Apache-2.0"}
authors = [{ name = "Iterative", email = "[email protected]" }]
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Development Status :: 4 - Beta",
]
requires-python = ">=3.8"
requires-python = ">=3.9"
dynamic = ["version"]
dependencies = [
"gitpython>3",
"dulwich>=0.21.6",
"pygit2>=1.13.3",
"pygit2>=1.14.0",
"pygtrie>=2.3.2",
"fsspec>=2021.7.0",
"pathspec>=0.9.0",
Expand All @@ -48,7 +48,7 @@ tests = [
"pytest-test-utils==0.0.8",
"pytest-asyncio==0.18.3",
# https://github.com/docker/docker-py/issues/2902
"pytest-docker==0.12.0; python_version < '3.10' and implementation_name != 'pypy'",
"pytest-docker==2.2.0; python_version < '3.10' and implementation_name != 'pypy'",
"mock==5.1.0",
"paramiko==3.3.1",
"types-certifi==2021.10.8.3",
Expand Down
6 changes: 3 additions & 3 deletions src/scmrepo/asyn.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import asyncio
import os
import threading
from typing import Any, List, Optional
from typing import Any, Optional

from fsspec.asyn import ( # noqa: F401, pylint:disable=unused-import
_selector_policy,
Expand All @@ -11,9 +11,9 @@
)

# dedicated async IO thread
iothread: List[Optional[threading.Thread]] = [None]
iothread: list[Optional[threading.Thread]] = [None]
# global DVC event loop
default_loop: List[Optional[asyncio.AbstractEventLoop]] = [None]
default_loop: list[Optional[asyncio.AbstractEventLoop]] = [None]
lock = threading.Lock()


Expand Down
8 changes: 4 additions & 4 deletions src/scmrepo/fs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import errno
import os
import posixpath
from typing import TYPE_CHECKING, Any, BinaryIO, Callable, Dict, Optional, Tuple
from typing import TYPE_CHECKING, Any, BinaryIO, Callable, Optional

from fsspec.callbacks import _DEFAULT_CALLBACK
from fsspec.spec import AbstractFileSystem
Expand Down Expand Up @@ -169,7 +169,7 @@ def relparts(self, path, start=None):
def as_posix(cls, path):
return path

def _get_key(self, path: str) -> Tuple[str, ...]:
def _get_key(self, path: str) -> tuple[str, ...]:
path = self.abspath(path)
if path == self.root_marker:
return ()
Expand All @@ -184,7 +184,7 @@ def _open(
mode: str = "rb",
block_size: Optional[int] = None,
autocommit: bool = True,
cache_options: Optional[Dict] = None,
cache_options: Optional[dict] = None,
raw: bool = False,
**kwargs: Any,
) -> BinaryIO:
Expand All @@ -204,7 +204,7 @@ def _open(
errno.EISDIR, os.strerror(errno.EISDIR), path
) from exc

def info(self, path: str, **kwargs: Any) -> Dict[str, Any]:
def info(self, path: str, **kwargs: Any) -> dict[str, Any]:
key = self._get_key(path)
try:
# NOTE: to avoid wasting time computing object size, trie.info
Expand Down
18 changes: 7 additions & 11 deletions src/scmrepo/git/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,14 @@
import re
import typing
from collections import OrderedDict
from collections.abc import Mapping
from collections.abc import Iterable, Mapping
from contextlib import contextmanager
from functools import partialmethod
from typing import (
TYPE_CHECKING,
Callable,
ClassVar,
Dict,
Iterable,
Optional,
Tuple,
Type,
Union,
)

Expand Down Expand Up @@ -44,14 +40,14 @@

logger = logging.getLogger(__name__)

BackendCls = Type[BaseGitBackend]
BackendCls = type[BaseGitBackend]


_LOW_PRIO_BACKENDS = ("gitpython",)


class GitBackends(Mapping):
DEFAULT: ClassVar[Dict[str, BackendCls]] = {
DEFAULT: ClassVar[dict[str, BackendCls]] = {
"dulwich": DulwichBackend,
"pygit2": Pygit2Backend,
"gitpython": GitPythonBackend,
Expand All @@ -72,7 +68,7 @@ def __init__(self, selected: Optional[Iterable[str]], *args, **kwargs) -> None:
selected = selected or list(self.DEFAULT)
self.backends = OrderedDict((key, self.DEFAULT[key]) for key in selected)

self.initialized: Dict[str, BaseGitBackend] = {}
self.initialized: dict[str, BaseGitBackend] = {}

self.args = args
self.kwargs = kwargs
Expand Down Expand Up @@ -169,7 +165,7 @@ def is_sha(cls, rev):
return rev and cls.RE_HEXSHA.search(rev)

@classmethod
def split_ref_pattern(cls, ref: str) -> Tuple[str, str]:
def split_ref_pattern(cls, ref: str) -> tuple[str, str]:
name = cls.BAD_REF_CHARS_RE.split(ref, maxsplit=1)[0]
return name, ref[len(name) :]

Expand Down Expand Up @@ -492,8 +488,8 @@ def describe(
base: Optional[str] = None,
match: Optional[str] = None,
exclude: Optional[str] = None,
) -> Dict[str, Optional[str]]:
results: Dict[str, Optional[str]] = {}
) -> dict[str, Optional[str]]:
results: dict[str, Optional[str]] = {}
remained_revs = set()
if base == "refs/heads":
current_rev = self.get_rev()
Expand Down
7 changes: 4 additions & 3 deletions src/scmrepo/git/backend/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import os
from abc import ABC, abstractmethod
from collections.abc import Iterable, Mapping
from enum import Enum
from typing import TYPE_CHECKING, Callable, Iterable, Mapping, Optional, Tuple, Union
from typing import TYPE_CHECKING, Callable, Optional, Union

from scmrepo.exceptions import SCMError
from scmrepo.git.objects import GitObject
Expand Down Expand Up @@ -281,7 +282,7 @@ def _stash_push(
ref: str,
message: Optional[str] = None,
include_untracked: bool = False,
) -> Tuple[Optional[str], bool]:
) -> tuple[Optional[str], bool]:
"""Push a commit onto the specified stash.

Returns a tuple of the form (rev, need_reset) where need_reset
Expand Down Expand Up @@ -347,7 +348,7 @@ def checkout_index(
@abstractmethod
def status(
self, ignored: bool = False, untracked_files: str = "all"
) -> Tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
) -> tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
"""Return tuple of (staged_files, unstaged_files, untracked_files).

staged_files will be a dict mapping status (add, delete, modify) to a
Expand Down
39 changes: 17 additions & 22 deletions src/scmrepo/git/backend/dulwich/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,15 @@
import os
import re
import stat
from collections.abc import Iterable, Iterator, Mapping
from contextlib import closing
from functools import partial
from io import BytesIO, StringIO
from typing import (
TYPE_CHECKING,
Any,
Callable,
Dict,
Iterable,
Iterator,
List,
Mapping,
Optional,
Tuple,
Union,
)

Expand Down Expand Up @@ -151,18 +146,18 @@ def encoding(self) -> str:
return self._config.encoding
return self._config.backends[0].encoding

def get(self, section: Tuple[str, ...], name: str) -> str:
def get(self, section: tuple[str, ...], name: str) -> str:
"""Return the specified setting as a string."""
return self._config.get(section, name).decode(self.encoding)

def get_bool(self, section: Tuple[str, ...], name: str) -> bool:
def get_bool(self, section: tuple[str, ...], name: str) -> bool:
"""Return the specified setting as a boolean."""
value = self._config.get_boolean(section, name)
if value is None:
raise ValueError("setting is not a valid boolean")
return value

def get_multivar(self, section: Tuple[str, ...], name: str) -> Iterator[str]:
def get_multivar(self, section: tuple[str, ...], name: str) -> Iterator[str]:
"""Iterate over string values in the specified multivar setting."""
for value in self._config.get_multivar(section, name):
yield value.decode(self.encoding)
Expand Down Expand Up @@ -199,17 +194,17 @@ def __init__( # pylint:disable=W0231
except NotGitRepository as exc:
raise SCMError(f"{root_dir} is not a git repository") from exc

self._submodules: Dict[str, str] = self._find_submodules()
self._submodules: dict[str, str] = self._find_submodules()
self._stashes: dict = {}

def _find_submodules(self) -> Dict[str, str]:
def _find_submodules(self) -> dict[str, str]:
"""Return dict mapping submodule names to submodule paths.

Submodule paths will be relative to Git repo root.
"""
from dulwich.config import ConfigFile, parse_submodules

submodules: Dict[str, str] = {}
submodules: dict[str, str] = {}
config_path = os.path.join(self.root_dir, ".gitmodules")
if os.path.isfile(config_path):
config = ConfigFile.from_path(config_path)
Expand Down Expand Up @@ -332,7 +327,7 @@ def add(
self.repo.stage(list(self.repo.open_index()))
return

files: List[bytes] = [
files: list[bytes] = [
os.fsencode(fpath) for fpath in self._expand_paths(paths, force=force)
]
if update:
Expand All @@ -348,7 +343,7 @@ def add(
else:
self.repo.stage(files)

def _expand_paths(self, paths: List[str], force: bool = False) -> Iterator[str]:
def _expand_paths(self, paths: list[str], force: bool = False) -> Iterator[str]:
for path in paths:
if not os.path.isabs(path) and self._submodules:
# NOTE: If path is inside a submodule, Dulwich expects the
Expand Down Expand Up @@ -459,7 +454,7 @@ def is_tracked(self, path: str) -> bool:
return any(p == rel or p.startswith(rel_dir) for p in self.repo.open_index())

def is_dirty(self, untracked_files: bool = False) -> bool:
kwargs: Dict[str, Any] = {} if untracked_files else {"untracked_files": "no"}
kwargs: dict[str, Any] = {} if untracked_files else {"untracked_files": "no"}
return any(self.status(**kwargs))

def active_branch(self) -> str:
Expand Down Expand Up @@ -707,9 +702,9 @@ def fetch_refspecs(
fetch_refs = []

def determine_wants(
remote_refs: Dict[bytes, bytes],
remote_refs: dict[bytes, bytes],
depth: Optional[int] = None, # pylint: disable=unused-argument
) -> List[bytes]:
) -> list[bytes]:
fetch_refs.extend(
parse_reftuples(
DictRefsContainer(remote_refs),
Expand Down Expand Up @@ -782,7 +777,7 @@ def _stash_push(
ref: str,
message: Optional[str] = None,
include_untracked: bool = False,
) -> Tuple[Optional[str], bool]:
) -> tuple[Optional[str], bool]:
from dulwich.repo import InvalidUserIdentity

from scmrepo.git import Stash
Expand Down Expand Up @@ -836,8 +831,8 @@ def _describe(
) -> Mapping[str, Optional[str]]:
if not base:
base = "refs/tags"
rev_mapping: Dict[str, Optional[str]] = {}
results: Dict[str, Optional[str]] = {}
rev_mapping: dict[str, Optional[str]] = {}
results: dict[str, Optional[str]] = {}
for ref in self.iter_refs(base=base):
if (match and not fnmatch.fnmatch(ref, match)) or (
exclude and fnmatch.fnmatch(ref, exclude)
Expand Down Expand Up @@ -877,7 +872,7 @@ def checkout_index(

def status(
self, ignored: bool = False, untracked_files: str = "all"
) -> Tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
) -> tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
from dulwich.porcelain import Error
from dulwich.porcelain import status as git_status

Expand Down Expand Up @@ -978,7 +973,7 @@ def check_attr(
_IDENTITY_RE = re.compile(r"(?P<name>.+)\s+<(?P<email>.+)>")


def _parse_identity(identity: str) -> Tuple[str, str]:
def _parse_identity(identity: str) -> tuple[str, str]:
m = _IDENTITY_RE.match(identity)
if not m:
raise SCMError("Could not parse tagger identity '{identity}'")
Expand Down
Loading