Skip to content

Commit 0d23565

Browse files
pygit2: bump to 1.14.0 (#312)
* pygit2: bump to 1.14.0 * pygit2: replace pygit2.remote with pygit2.remotes * Drop Python 3.8 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fixup! [pre-commit.ci] auto fixes from pre-commit.com hooks * Add support for Python 3.12 * Upgrade pytest-docker to v2 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 6e44250 commit 0d23565

28 files changed

+137
-157
lines changed

.github/workflows/tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
fail-fast: false
2222
matrix:
2323
os: [ubuntu-20.04, windows-latest, macos-latest]
24-
pyv: ['3.8', '3.9', '3.10', '3.11']
24+
pyv: ['3.9', '3.10', '3.11', '3.12']
2525

2626
steps:
2727
- name: Check out the repository

CONTRIBUTING.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Request features on the `Issue Tracker`_.
4141
How to set up your development environment
4242
------------------------------------------
4343

44-
You need Python 3.8+ and the following tools:
44+
You need Python 3.9+ and the following tools:
4545

4646
- Nox_
4747

noxfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
locations = "src", "tests"
1010

1111

12-
@nox.session(python=["3.8", "3.9", "3.10", "3.11"])
12+
@nox.session(python=["3.9", "3.10", "3.11", "3.12"])
1313
def tests(session: nox.Session) -> None:
1414
session.install(".[tests]")
1515
session.run(

pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ license = {text = "Apache-2.0"}
1212
authors = [{ name = "Iterative", email = "[email protected]" }]
1313
classifiers = [
1414
"Programming Language :: Python :: 3",
15-
"Programming Language :: Python :: 3.8",
1615
"Programming Language :: Python :: 3.9",
1716
"Programming Language :: Python :: 3.10",
1817
"Programming Language :: Python :: 3.11",
18+
"Programming Language :: Python :: 3.12",
1919
"Development Status :: 4 - Beta",
2020
]
21-
requires-python = ">=3.8"
21+
requires-python = ">=3.9"
2222
dynamic = ["version"]
2323
dependencies = [
2424
"gitpython>3",
2525
"dulwich>=0.21.6",
26-
"pygit2>=1.13.3",
26+
"pygit2>=1.14.0",
2727
"pygtrie>=2.3.2",
2828
"fsspec>=2021.7.0",
2929
"pathspec>=0.9.0",
@@ -48,7 +48,7 @@ tests = [
4848
"pytest-test-utils==0.0.8",
4949
"pytest-asyncio==0.18.3",
5050
# https://github.com/docker/docker-py/issues/2902
51-
"pytest-docker==0.12.0; python_version < '3.10' and implementation_name != 'pypy'",
51+
"pytest-docker==2.2.0; python_version < '3.10' and implementation_name != 'pypy'",
5252
"mock==5.1.0",
5353
"paramiko==3.3.1",
5454
"types-certifi==2021.10.8.3",

src/scmrepo/asyn.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import asyncio
33
import os
44
import threading
5-
from typing import Any, List, Optional
5+
from typing import Any, Optional
66

77
from fsspec.asyn import ( # noqa: F401, pylint:disable=unused-import
88
_selector_policy,
@@ -11,9 +11,9 @@
1111
)
1212

1313
# dedicated async IO thread
14-
iothread: List[Optional[threading.Thread]] = [None]
14+
iothread: list[Optional[threading.Thread]] = [None]
1515
# global DVC event loop
16-
default_loop: List[Optional[asyncio.AbstractEventLoop]] = [None]
16+
default_loop: list[Optional[asyncio.AbstractEventLoop]] = [None]
1717
lock = threading.Lock()
1818

1919

src/scmrepo/fs.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import errno
22
import os
33
import posixpath
4-
from typing import TYPE_CHECKING, Any, BinaryIO, Callable, Dict, Optional, Tuple
4+
from typing import TYPE_CHECKING, Any, BinaryIO, Callable, Optional
55

66
from fsspec.callbacks import _DEFAULT_CALLBACK
77
from fsspec.spec import AbstractFileSystem
@@ -169,7 +169,7 @@ def relparts(self, path, start=None):
169169
def as_posix(cls, path):
170170
return path
171171

172-
def _get_key(self, path: str) -> Tuple[str, ...]:
172+
def _get_key(self, path: str) -> tuple[str, ...]:
173173
path = self.abspath(path)
174174
if path == self.root_marker:
175175
return ()
@@ -184,7 +184,7 @@ def _open(
184184
mode: str = "rb",
185185
block_size: Optional[int] = None,
186186
autocommit: bool = True,
187-
cache_options: Optional[Dict] = None,
187+
cache_options: Optional[dict] = None,
188188
raw: bool = False,
189189
**kwargs: Any,
190190
) -> BinaryIO:
@@ -204,7 +204,7 @@ def _open(
204204
errno.EISDIR, os.strerror(errno.EISDIR), path
205205
) from exc
206206

207-
def info(self, path: str, **kwargs: Any) -> Dict[str, Any]:
207+
def info(self, path: str, **kwargs: Any) -> dict[str, Any]:
208208
key = self._get_key(path)
209209
try:
210210
# NOTE: to avoid wasting time computing object size, trie.info

src/scmrepo/git/__init__.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,14 @@
55
import re
66
import typing
77
from collections import OrderedDict
8-
from collections.abc import Mapping
8+
from collections.abc import Iterable, Mapping
99
from contextlib import contextmanager
1010
from functools import partialmethod
1111
from typing import (
1212
TYPE_CHECKING,
1313
Callable,
1414
ClassVar,
15-
Dict,
16-
Iterable,
1715
Optional,
18-
Tuple,
19-
Type,
2016
Union,
2117
)
2218

@@ -44,14 +40,14 @@
4440

4541
logger = logging.getLogger(__name__)
4642

47-
BackendCls = Type[BaseGitBackend]
43+
BackendCls = type[BaseGitBackend]
4844

4945

5046
_LOW_PRIO_BACKENDS = ("gitpython",)
5147

5248

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

75-
self.initialized: Dict[str, BaseGitBackend] = {}
71+
self.initialized: dict[str, BaseGitBackend] = {}
7672

7773
self.args = args
7874
self.kwargs = kwargs
@@ -169,7 +165,7 @@ def is_sha(cls, rev):
169165
return rev and cls.RE_HEXSHA.search(rev)
170166

171167
@classmethod
172-
def split_ref_pattern(cls, ref: str) -> Tuple[str, str]:
168+
def split_ref_pattern(cls, ref: str) -> tuple[str, str]:
173169
name = cls.BAD_REF_CHARS_RE.split(ref, maxsplit=1)[0]
174170
return name, ref[len(name) :]
175171

@@ -492,8 +488,8 @@ def describe(
492488
base: Optional[str] = None,
493489
match: Optional[str] = None,
494490
exclude: Optional[str] = None,
495-
) -> Dict[str, Optional[str]]:
496-
results: Dict[str, Optional[str]] = {}
491+
) -> dict[str, Optional[str]]:
492+
results: dict[str, Optional[str]] = {}
497493
remained_revs = set()
498494
if base == "refs/heads":
499495
current_rev = self.get_rev()

src/scmrepo/git/backend/base.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import os
22
from abc import ABC, abstractmethod
3+
from collections.abc import Iterable, Mapping
34
from enum import Enum
4-
from typing import TYPE_CHECKING, Callable, Iterable, Mapping, Optional, Tuple, Union
5+
from typing import TYPE_CHECKING, Callable, Optional, Union
56

67
from scmrepo.exceptions import SCMError
78
from scmrepo.git.objects import GitObject
@@ -281,7 +282,7 @@ def _stash_push(
281282
ref: str,
282283
message: Optional[str] = None,
283284
include_untracked: bool = False,
284-
) -> Tuple[Optional[str], bool]:
285+
) -> tuple[Optional[str], bool]:
285286
"""Push a commit onto the specified stash.
286287
287288
Returns a tuple of the form (rev, need_reset) where need_reset
@@ -347,7 +348,7 @@ def checkout_index(
347348
@abstractmethod
348349
def status(
349350
self, ignored: bool = False, untracked_files: str = "all"
350-
) -> Tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
351+
) -> tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
351352
"""Return tuple of (staged_files, unstaged_files, untracked_files).
352353
353354
staged_files will be a dict mapping status (add, delete, modify) to a

src/scmrepo/git/backend/dulwich/__init__.py

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,15 @@
44
import os
55
import re
66
import stat
7+
from collections.abc import Iterable, Iterator, Mapping
78
from contextlib import closing
89
from functools import partial
910
from io import BytesIO, StringIO
1011
from typing import (
1112
TYPE_CHECKING,
1213
Any,
1314
Callable,
14-
Dict,
15-
Iterable,
16-
Iterator,
17-
List,
18-
Mapping,
1915
Optional,
20-
Tuple,
2116
Union,
2217
)
2318

@@ -151,18 +146,18 @@ def encoding(self) -> str:
151146
return self._config.encoding
152147
return self._config.backends[0].encoding
153148

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

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

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

202-
self._submodules: Dict[str, str] = self._find_submodules()
197+
self._submodules: dict[str, str] = self._find_submodules()
203198
self._stashes: dict = {}
204199

205-
def _find_submodules(self) -> Dict[str, str]:
200+
def _find_submodules(self) -> dict[str, str]:
206201
"""Return dict mapping submodule names to submodule paths.
207202
208203
Submodule paths will be relative to Git repo root.
209204
"""
210205
from dulwich.config import ConfigFile, parse_submodules
211206

212-
submodules: Dict[str, str] = {}
207+
submodules: dict[str, str] = {}
213208
config_path = os.path.join(self.root_dir, ".gitmodules")
214209
if os.path.isfile(config_path):
215210
config = ConfigFile.from_path(config_path)
@@ -332,7 +327,7 @@ def add(
332327
self.repo.stage(list(self.repo.open_index()))
333328
return
334329

335-
files: List[bytes] = [
330+
files: list[bytes] = [
336331
os.fsencode(fpath) for fpath in self._expand_paths(paths, force=force)
337332
]
338333
if update:
@@ -348,7 +343,7 @@ def add(
348343
else:
349344
self.repo.stage(files)
350345

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

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

465460
def active_branch(self) -> str:
@@ -707,9 +702,9 @@ def fetch_refspecs(
707702
fetch_refs = []
708703

709704
def determine_wants(
710-
remote_refs: Dict[bytes, bytes],
705+
remote_refs: dict[bytes, bytes],
711706
depth: Optional[int] = None, # pylint: disable=unused-argument
712-
) -> List[bytes]:
707+
) -> list[bytes]:
713708
fetch_refs.extend(
714709
parse_reftuples(
715710
DictRefsContainer(remote_refs),
@@ -782,7 +777,7 @@ def _stash_push(
782777
ref: str,
783778
message: Optional[str] = None,
784779
include_untracked: bool = False,
785-
) -> Tuple[Optional[str], bool]:
780+
) -> tuple[Optional[str], bool]:
786781
from dulwich.repo import InvalidUserIdentity
787782

788783
from scmrepo.git import Stash
@@ -836,8 +831,8 @@ def _describe(
836831
) -> Mapping[str, Optional[str]]:
837832
if not base:
838833
base = "refs/tags"
839-
rev_mapping: Dict[str, Optional[str]] = {}
840-
results: Dict[str, Optional[str]] = {}
834+
rev_mapping: dict[str, Optional[str]] = {}
835+
results: dict[str, Optional[str]] = {}
841836
for ref in self.iter_refs(base=base):
842837
if (match and not fnmatch.fnmatch(ref, match)) or (
843838
exclude and fnmatch.fnmatch(ref, exclude)
@@ -877,7 +872,7 @@ def checkout_index(
877872

878873
def status(
879874
self, ignored: bool = False, untracked_files: str = "all"
880-
) -> Tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
875+
) -> tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
881876
from dulwich.porcelain import Error
882877
from dulwich.porcelain import status as git_status
883878

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

980975

981-
def _parse_identity(identity: str) -> Tuple[str, str]:
976+
def _parse_identity(identity: str) -> tuple[str, str]:
982977
m = _IDENTITY_RE.match(identity)
983978
if not m:
984979
raise SCMError("Could not parse tagger identity '{identity}'")

0 commit comments

Comments
 (0)