diff options
author | Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> | 2022-05-07 21:37:00 +0200 |
---|---|---|
committer | Ronny Pfannschmidt <opensource@ronnypfannschmidt.de> | 2022-05-29 12:29:31 +0200 |
commit | d65a0377a71b2915107d4e816c0f5e1724d42f82 (patch) | |
tree | a2151669029385f007fe6092afbb358c761b2179 | |
parent | b45e19f9f275a31873fd5e07faabef16fd0bbec0 (diff) | |
download | setuptools-scm-d65a0377a71b2915107d4e816c0f5e1724d42f82.tar.gz |
Bump minimal python to 3.7
40 files changed, 217 insertions, 208 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ba8933a..43e396d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ repos: rev: v3.1.0 hooks: - id: reorder-python-imports - args: [ "--application-directories=.:src" , --py3-plus] + args: [ "--application-directories=.:src" , --py37-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.2.0 hooks: @@ -26,7 +26,7 @@ repos: rev: v2.32.0 hooks: - id: pyupgrade - args: [--py36-plus] + args: [--py37-plus] - repo: https://github.com/asottile/setup-cfg-fmt rev: v1.20.1 hooks: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 74f0f5a..80b5523 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,10 @@ +v7.0.0 +======= + +* drop python 3.6 support +* include git archival support + + v6.4.3 ====== @@ -1,5 +1,5 @@ [mypy] -python_version = 3.6 +python_version = 3.7 warn_return_any = True warn_unused_configs = True mypy_path = $MYPY_CONFIG_FILE_DIR/src @@ -7,4 +7,4 @@ mypy_path = $MYPY_CONFIG_FILE_DIR/src [mypy-setuptools_scm.*] # disabled as it will take a bit # disallow_untyped_defs = True -# strict = true +strict = true @@ -15,7 +15,6 @@ classifiers = Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -31,7 +30,7 @@ install_requires = packaging>=20.0 setuptools tomli>=1.0.0 # keep in sync -python_requires = >=3.6 +python_requires = >=3.7 package_dir = =src zip_safe = true @@ -9,29 +9,15 @@ once before running sdist or easy_install on a fresh checkouts pip usage is recommended """ +from __future__ import annotations + import os import sys -from typing import NoReturn -from typing import Optional import setuptools -from setuptools.command.bdist_egg import bdist_egg as original_bdist_egg - - -class bdist_egg(original_bdist_egg): - def run(self) -> NoReturn: - raise SystemExit( - "%s is forbidden, " - "please update to setuptools>=45 which uses pip" % type(self).__name__ - ) def scm_version() -> str: - - if sys.version_info < (3, 6): - raise RuntimeError( - "support for python < 3.6 has been removed in setuptools_scm>=6.0.0" - ) here = os.path.dirname(os.path.abspath(__file__)) src = os.path.join(here, "src") @@ -46,7 +32,7 @@ def scm_version() -> str: from setuptools_scm.version import ScmVersion - def parse(root: str, config: Configuration) -> Optional[ScmVersion]: + def parse(root: str, config: Configuration) -> ScmVersion | None: try: return parse_pkginfo(root, config) except OSError: @@ -69,5 +55,4 @@ if __name__ == "__main__": ], "test": ["pytest>=6.2", "virtualenv>20"], }, - cmdclass={"bdist_egg": bdist_egg}, ) diff --git a/src/setuptools_scm/__init__.py b/src/setuptools_scm/__init__.py index 9e53371..6edf3e4 100644 --- a/src/setuptools_scm/__init__.py +++ b/src/setuptools_scm/__init__.py @@ -2,13 +2,13 @@ :copyright: 2010-2015 by Ronny Pfannschmidt :license: MIT """ +from __future__ import annotations + import os import warnings from typing import Any from typing import Callable -from typing import Optional from typing import TYPE_CHECKING -from typing import Union from . import _types as _t from ._entrypoints import _call_entrypoint_fn @@ -46,7 +46,7 @@ __version_tuple__ = version_tuple = {version_tuple!r} } -def version_from_scm(root: _t.PathT) -> Optional[ScmVersion]: +def version_from_scm(root: _t.PathT) -> ScmVersion | None: warnings.warn( "version_from_scm is deprecated please use get_version", category=DeprecationWarning, @@ -60,7 +60,7 @@ def dump_version( root: _t.PathT, version: str, write_to: _t.PathT, - template: "str | None" = None, + template: str | None = None, ) -> None: assert isinstance(version, str) target = os.path.normpath(os.path.join(root, write_to)) @@ -79,7 +79,7 @@ def dump_version( fp.write(template.format(version=version, version_tuple=version_tuple)) -def _do_parse(config: Configuration) -> "ScmVersion|None": +def _do_parse(config: Configuration) -> ScmVersion | None: pretended = _read_pretended_version_for(config) if pretended is not None: return pretended @@ -90,7 +90,7 @@ def _do_parse(config: Configuration) -> "ScmVersion|None": raise TypeError( f"version parse result was {str!r}\nplease return a parsed version" ) - version: Optional[ScmVersion] + version: ScmVersion | None if parse_result: assert isinstance(parse_result, ScmVersion) version = parse_result @@ -105,7 +105,7 @@ def _do_parse(config: Configuration) -> "ScmVersion|None": return version -def _version_missing(config: Configuration) -> "NoReturn": +def _version_missing(config: Configuration) -> NoReturn: raise LookupError( f"setuptools-scm was unable to detect version for {config.absolute_root}.\n\n" "Make sure you're either building from a fully intact git repository " @@ -120,19 +120,19 @@ def _version_missing(config: Configuration) -> "NoReturn": def get_version( root: str = ".", - version_scheme: Union[Callable[[ScmVersion], str], str] = DEFAULT_VERSION_SCHEME, - local_scheme: Union[Callable[[ScmVersion], str], str] = DEFAULT_LOCAL_SCHEME, - write_to: Optional[_t.PathT] = None, - write_to_template: Optional[str] = None, - relative_to: Optional[str] = None, + version_scheme: Callable[[ScmVersion], str] | str = DEFAULT_VERSION_SCHEME, + local_scheme: Callable[[ScmVersion], str] | str = DEFAULT_LOCAL_SCHEME, + write_to: _t.PathT | None = None, + write_to_template: str | None = None, + relative_to: str | None = None, tag_regex: str = DEFAULT_TAG_REGEX, - parentdir_prefix_version: Optional[str] = None, - fallback_version: Optional[str] = None, + parentdir_prefix_version: str | None = None, + fallback_version: str | None = None, fallback_root: _t.PathT = ".", - parse: Optional[Any] = None, - git_describe_command: Optional[Any] = None, - dist_name: Optional[str] = None, - version_cls: Optional[Any] = None, + parse: Any | None = None, + git_describe_command: Any | None = None, + dist_name: str | None = None, + version_cls: Any | None = None, normalize: bool = True, search_parent_directories: bool = False, ) -> str: @@ -150,7 +150,7 @@ def get_version( return maybe_version -def _get_version(config: Configuration) -> "str|None": +def _get_version(config: Configuration) -> str | None: parsed_version = _do_parse(config) if parsed_version is None: return None diff --git a/src/setuptools_scm/__main__.py b/src/setuptools_scm/__main__.py index 1b61679..dab6068 100644 --- a/src/setuptools_scm/__main__.py +++ b/src/setuptools_scm/__main__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from ._cli import main if __name__ == "__main__": diff --git a/src/setuptools_scm/_cli.py b/src/setuptools_scm/_cli.py index 0e0ad77..88dd6d0 100644 --- a/src/setuptools_scm/_cli.py +++ b/src/setuptools_scm/_cli.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import argparse import os import sys diff --git a/src/setuptools_scm/_entrypoints.py b/src/setuptools_scm/_entrypoints.py index 299ddaa..134ec4f 100644 --- a/src/setuptools_scm/_entrypoints.py +++ b/src/setuptools_scm/_entrypoints.py @@ -1,7 +1,8 @@ +from __future__ import annotations + import warnings from typing import Any from typing import Iterator -from typing import Optional from typing import overload from typing import Protocol from typing import TYPE_CHECKING @@ -21,17 +22,17 @@ class MaybeConfigFunction(Protocol): __name__: str @overload - def __call__(self, root: _t.PathT, config: Configuration) -> Optional[ScmVersion]: + def __call__(self, root: _t.PathT, config: Configuration) -> ScmVersion | None: pass @overload - def __call__(self, root: _t.PathT) -> Optional[ScmVersion]: + def __call__(self, root: _t.PathT) -> ScmVersion | None: pass def _call_entrypoint_fn( root: _t.PathT, config: Configuration, fn: MaybeConfigFunction -) -> Optional[ScmVersion]: +) -> ScmVersion | None: if function_has_arg(fn, "config"): return fn(root, config=config) else: @@ -47,7 +48,7 @@ def _call_entrypoint_fn( def _version_from_entrypoints( config: Configuration, fallback: bool = False -) -> "ScmVersion|None": +) -> ScmVersion | None: if fallback: entrypoint = "setuptools_scm.parse_scm_fallback" root = config.fallback_root @@ -59,7 +60,7 @@ def _version_from_entrypoints( trace("version_from_ep", entrypoint, root) for ep in iter_matching_entrypoints(root, entrypoint, config): - version: Optional[ScmVersion] = _call_entrypoint_fn(root, config, ep.load()) + version: ScmVersion | None = _call_entrypoint_fn(root, config, ep.load()) trace(ep, version) if version: return version @@ -73,7 +74,7 @@ except ImportError: def iter_entry_points( - group: str, name: Optional[str] = None + group: str, name: str | None = None ) -> Iterator[_t.EntrypointProtocol]: all_eps = entry_points() if hasattr(all_eps, "select"): diff --git a/src/setuptools_scm/_overrides.py b/src/setuptools_scm/_overrides.py index 00876e0..f18b82c 100644 --- a/src/setuptools_scm/_overrides.py +++ b/src/setuptools_scm/_overrides.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import os -from typing import Optional from .config import Configuration from .utils import trace @@ -11,14 +12,14 @@ PRETEND_KEY = "SETUPTOOLS_SCM_PRETEND_VERSION" PRETEND_KEY_NAMED = PRETEND_KEY + "_FOR_{name}" -def _read_pretended_version_for(config: Configuration) -> Optional[ScmVersion]: +def _read_pretended_version_for(config: Configuration) -> ScmVersion | None: """read a a overridden version from the environment tries ``SETUPTOOLS_SCM_PRETEND_VERSION`` and ``SETUPTOOLS_SCM_PRETEND_VERSION_FOR_$UPPERCASE_DIST_NAME`` """ trace("dist name:", config.dist_name) - pretended: Optional[str] + pretended: str | None if config.dist_name is not None: pretended = os.environ.get( PRETEND_KEY_NAMED.format(name=config.dist_name.upper()) diff --git a/src/setuptools_scm/_types.py b/src/setuptools_scm/_types.py index 09fb2b6..7849eae 100644 --- a/src/setuptools_scm/_types.py +++ b/src/setuptools_scm/_types.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import sys from typing import Any diff --git a/src/setuptools_scm/_version_cls.py b/src/setuptools_scm/_version_cls.py index 7bde4b2..39e66b2 100644 --- a/src/setuptools_scm/_version_cls.py +++ b/src/setuptools_scm/_version_cls.py @@ -1,6 +1,6 @@ +from __future__ import annotations + from logging import getLogger -from typing import Tuple -from typing import Union from packaging.version import InvalidVersion from packaging.version import Version as Version @@ -31,7 +31,7 @@ class NonNormalizedVersion(Version): return f"<NonNormalizedVersion({self._raw_version!r})>" -def _version_as_tuple(version_str: str) -> Tuple[Union[int, str], ...]: +def _version_as_tuple(version_str: str) -> tuple[int | str, ...]: try: parsed_version = Version(version_str) except InvalidVersion: @@ -40,7 +40,7 @@ def _version_as_tuple(version_str: str) -> Tuple[Union[int, str], ...]: log.exception("failed to parse version %s", version_str) return (version_str,) else: - version_fields: Tuple[Union[int, str], ...] = parsed_version.release + version_fields: tuple[int | str, ...] = parsed_version.release if parsed_version.dev is not None: version_fields += (f"dev{parsed_version.dev}",) if parsed_version.local is not None: diff --git a/src/setuptools_scm/config.py b/src/setuptools_scm/config.py index eba15e9..a8bccdf 100644 --- a/src/setuptools_scm/config.py +++ b/src/setuptools_scm/config.py @@ -1,13 +1,12 @@ """ configuration """ +from __future__ import annotations + import os import re import warnings from typing import Any from typing import Callable -from typing import Dict -from typing import Optional from typing import Pattern -from typing import Type from typing import TYPE_CHECKING from typing import Union @@ -25,7 +24,7 @@ DEFAULT_VERSION_SCHEME = "guess-next-dev" DEFAULT_LOCAL_SCHEME = "node-and-date" -def _check_tag_regex(value: Optional[Union[str, Pattern[str]]]) -> Pattern[str]: +def _check_tag_regex(value: str | Pattern[str] | None) -> Pattern[str]: if not value: value = DEFAULT_TAG_REGEX regex = re.compile(value) @@ -40,7 +39,7 @@ def _check_tag_regex(value: Optional[Union[str, Pattern[str]]]) -> Pattern[str]: return regex -def _check_absolute_root(root: _t.PathT, relative_to: Optional[_t.PathT]) -> str: +def _check_absolute_root(root: _t.PathT, relative_to: _t.PathT | None) -> str: trace("abs root", repr(locals())) if relative_to: if ( @@ -65,7 +64,7 @@ def _check_absolute_root(root: _t.PathT, relative_to: Optional[_t.PathT]) -> str return os.path.abspath(root) -def _lazy_tomli_load(data: str) -> Dict[str, Any]: +def _lazy_tomli_load(data: str) -> dict[str, Any]: from tomli import loads return loads(data) @@ -77,31 +76,33 @@ VersionT = Union[Version, NonNormalizedVersion] class Configuration: """Global configuration model""" - parent: Optional[_t.PathT] + parent: _t.PathT | None _root: str - _relative_to: Optional[str] - version_cls: Type[VersionT] + _relative_to: str | None + version_cls: type[VersionT] def __init__( self, - relative_to: "_t.PathT | None" = None, + relative_to: _t.PathT | None = None, root: _t.PathT = ".", - version_scheme: Union[ - str, Callable[["ScmVersion"], Optional[str]] - ] = DEFAULT_VERSION_SCHEME, - local_scheme: Union[ - str, Callable[["ScmVersion"], Optional[str]] - ] = DEFAULT_LOCAL_SCHEME, - write_to: "_t.PathT | None" = None, - write_to_template: "str|None" = None, - tag_regex: "str | Pattern[str]" = DEFAULT_TAG_REGEX, - parentdir_prefix_version: "str|None" = None, - fallback_version: "str|None" = None, + version_scheme: ( + str | Callable[[ScmVersion], str | None] + ) = DEFAULT_VERSION_SCHEME, + local_scheme: (str | Callable[[ScmVersion], str | None]) = DEFAULT_LOCAL_SCHEME, + write_to: _t.PathT | None = None, + write_to_template: str | None = None, + tag_regex: str | Pattern[str] = DEFAULT_TAG_REGEX, + parentdir_prefix_version: str | None = None, + fallback_version: str | None = None, fallback_root: _t.PathT = ".", - parse: Optional[Any] = None, - git_describe_command: Optional[_t.CMD_TYPE] = None, - dist_name: "str|None" = None, - version_cls: "Type[Version]|Type[NonNormalizedVersion]|type|str|None" = None, + parse: Any | None = None, + git_describe_command: _t.CMD_TYPE | None = None, + dist_name: str | None = None, + version_cls: type[Version] + | type[NonNormalizedVersion] + | type + | str + | None = None, normalize: bool = True, search_parent_directories: bool = False, ): @@ -162,7 +163,7 @@ class Configuration: return self._absolute_root @property - def relative_to(self) -> Optional[str]: + def relative_to(self) -> str | None: return self._relative_to @relative_to.setter @@ -188,17 +189,17 @@ class Configuration: return self._tag_regex @tag_regex.setter - def tag_regex(self, value: Union[str, Pattern[str]]) -> None: + def tag_regex(self, value: str | Pattern[str]) -> None: self._tag_regex = _check_tag_regex(value) @classmethod def from_file( cls, name: str = "pyproject.toml", - dist_name: Optional[str] = None, - _load_toml: Callable[[str], Dict[str, Any]] = _lazy_tomli_load, + dist_name: str | None = None, + _load_toml: Callable[[str], dict[str, Any]] = _lazy_tomli_load, **kwargs: Any, - ) -> "Configuration": + ) -> Configuration: """ Read Configuration from pyproject.toml (or similar). Raises exceptions when file is not found or toml is @@ -231,7 +232,7 @@ class Configuration: return cls(dist_name=dist_name, **section, **kwargs) -def _read_dist_name_from_setup_cfg() -> Optional[str]: +def _read_dist_name_from_setup_cfg() -> str | None: # minimal effort to read dist_name off setup.cfg metadata import configparser diff --git a/src/setuptools_scm/discover.py b/src/setuptools_scm/discover.py index 84fd3ef..87533fd 100644 --- a/src/setuptools_scm/discover.py +++ b/src/setuptools_scm/discover.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os from typing import Iterable from typing import Iterator diff --git a/src/setuptools_scm/file_finder.py b/src/setuptools_scm/file_finder.py index 741cb9e..f4ef9bb 100644 --- a/src/setuptools_scm/file_finder.py +++ b/src/setuptools_scm/file_finder.py @@ -1,4 +1,4 @@ -from __future__ import annotations # type: ignore +from __future__ import annotations import os from typing import TYPE_CHECKING diff --git a/src/setuptools_scm/file_finder_git.py b/src/setuptools_scm/file_finder_git.py index 922369a..c7ac5da 100644 --- a/src/setuptools_scm/file_finder_git.py +++ b/src/setuptools_scm/file_finder_git.py @@ -1,12 +1,10 @@ +from __future__ import annotations + import logging import os import subprocess import tarfile from typing import IO -from typing import List -from typing import Optional -from typing import Set -from typing import Tuple from . import _types as _t from .file_finder import is_toplevel_acceptable @@ -17,7 +15,7 @@ from .utils import trace log = logging.getLogger(__name__) -def _git_toplevel(path: str) -> Optional[str]: +def _git_toplevel(path: str) -> str | None: try: cwd = os.path.abspath(path or ".") out, err, ret = do_ex(["git", "rev-parse", "HEAD"], cwd=cwd) @@ -54,7 +52,7 @@ def _git_toplevel(path: str) -> Optional[str]: return None -def _git_interpret_archive(fd: IO[bytes], toplevel: str) -> Tuple[Set[str], Set[str]]: +def _git_interpret_archive(fd: IO[bytes], toplevel: str) -> tuple[set[str], set[str]]: with tarfile.open(fileobj=fd, mode="r|*") as tf: git_files = set() git_dirs = {toplevel} @@ -67,7 +65,7 @@ def _git_interpret_archive(fd: IO[bytes], toplevel: str) -> Tuple[Set[str], Set[ return git_files, git_dirs -def _git_ls_files_and_dirs(toplevel: str) -> Tuple[Set[str], Set[str]]: +def _git_ls_files_and_dirs(toplevel: str) -> tuple[set[str], set[str]]: # use git archive instead of git ls-file to honor # export-ignore git attribute @@ -89,7 +87,7 @@ def _git_ls_files_and_dirs(toplevel: str) -> Tuple[Set[str], Set[str]]: return set(), set() -def git_find_files(path: _t.PathT = "") -> List[str]: +def git_find_files(path: _t.PathT = "") -> list[str]: toplevel = _git_toplevel(os.fspath(path)) if not is_toplevel_acceptable(toplevel): return [] diff --git a/src/setuptools_scm/file_finder_hg.py b/src/setuptools_scm/file_finder_hg.py index 3523179..4f5e3ec 100644 --- a/src/setuptools_scm/file_finder_hg.py +++ b/src/setuptools_scm/file_finder_hg.py @@ -1,24 +1,21 @@ +from __future__ import annotations + import os import subprocess -from typing import List -from typing import Optional -from typing import Set -from typing import Tuple from .file_finder import is_toplevel_acceptable from .file_finder import scm_find_files from .utils import do_ex -def _hg_toplevel(path: str) -> Optional[str]: +def _hg_toplevel(path: str) -> str | None: try: - with open(os.devnull, "wb") as devnull: - out = subprocess.check_output( - ["hg", "root"], - cwd=(path or "."), - universal_newlines=True, - stderr=devnull, - ) + out: str = subprocess.check_output( + ["hg", "root"], + cwd=(path or "."), + text=True, + stderr=subprocess.DEVNULL, + ) return os.path.normcase(os.path.realpath(out.strip())) except subprocess.CalledProcessError: # hg returned error, we are not in a mercurial repo @@ -28,8 +25,8 @@ def _hg_toplevel(path: str) -> Optional[str]: return None -def _hg_ls_files_and_dirs(toplevel: str) -> Tuple[Set[str], Set[str]]: - hg_files: Set[str] = set() +def _hg_ls_files_and_dirs(toplevel: str) -> tuple[set[str], set[str]]: + hg_files: set[str] = set() hg_dirs = {toplevel} out, err, ret = do_ex(["hg", "files"], cwd=toplevel) if ret: @@ -45,7 +42,7 @@ def _hg_ls_files_and_dirs(toplevel: str) -> Tuple[Set[str], Set[str]]: return hg_files, hg_dirs -def hg_find_files(path: str = "") -> List[str]: +def hg_find_files(path: str = "") -> list[str]: toplevel = _hg_toplevel(path) if not is_toplevel_acceptable(toplevel): return [] diff --git a/src/setuptools_scm/git.py b/src/setuptools_scm/git.py index 875d80a..e417be0 100644 --- a/src/setuptools_scm/git.py +++ b/src/setuptools_scm/git.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import re import warnings @@ -7,12 +9,7 @@ from os.path import isfile from os.path import join from os.path import samefile from typing import Callable -from typing import Dict -from typing import List -from typing import Optional -from typing import Tuple from typing import TYPE_CHECKING -from typing import Union from . import _types as _t from .config import Configuration @@ -51,7 +48,7 @@ class GitWorkdir(Workdir): COMMAND = "git" @classmethod - def from_potential_worktree(cls, wd: _t.PathT) -> Optional["GitWorkdir"]: + def from_potential_worktree(cls, wd: _t.PathT) -> GitWorkdir | None: require_command(cls.COMMAND) wd = os.path.abspath(wd) real_wd, _, ret = do_ex("git rev-parse --show-prefix", wd) @@ -76,7 +73,7 @@ class GitWorkdir(Workdir): out, _, _ = self.do_ex("git status --porcelain --untracked-files=no") return bool(out) - def get_branch(self) -> Optional[str]: + def get_branch(self) -> str | None: branch, err, ret = self.do_ex("git rev-parse --abbrev-ref HEAD") if ret: trace("branch err", branch, err, ret) @@ -86,7 +83,7 @@ class GitWorkdir(Workdir): return None return branch - def get_head_date(self) -> Optional[date]: + def get_head_date(self) -> date | None: timestamp, err, ret = self.do_ex( "git -c log.showSignature=false log -n 1 HEAD --format=%cI" ) @@ -106,7 +103,7 @@ class GitWorkdir(Workdir): def fetch_shallow(self) -> None: self.do_ex("git fetch --unshallow") - def node(self) -> Optional[str]: + def node(self) -> str | None: node, _, ret = self.do_ex("git rev-parse --verify --quiet HEAD") if not ret: return node[:7] @@ -142,7 +139,7 @@ def fail_on_shallow(wd: GitWorkdir) -> None: ) -def get_working_directory(config: Configuration) -> Optional[GitWorkdir]: +def get_working_directory(config: Configuration) -> GitWorkdir | None: """ Return the working directory (``GitWorkdir``). """ @@ -158,10 +155,10 @@ def get_working_directory(config: Configuration) -> Optional[GitWorkdir]: def parse( root: str, - describe_command: Optional[Union[str, List[str]]] = None, + describe_command: str | list[str] | None = None, pre_parse: Callable[[GitWorkdir], None] = warn_on_shallow, - config: Optional[Configuration] = None, -) -> Optional[ScmVersion]: + config: Configuration | None = None, +) -> ScmVersion | None: """ :param pre_parse: experimental pre_parse action, may change at any time """ @@ -179,11 +176,9 @@ def parse( def _git_parse_inner( config: Configuration, - wd: Union[GitWorkdir, "GitWorkdirHgClient"], - pre_parse: Optional[ - Callable[[Union[GitWorkdir, "GitWorkdirHgClient"]], None] - ] = None, - describe_command: Optional[_t.CMD_TYPE] = None, + wd: GitWorkdir | GitWorkdirHgClient, + pre_parse: None | (Callable[[GitWorkdir | GitWorkdirHgClient], None]) = None, + describe_command: _t.CMD_TYPE | None = None, ) -> ScmVersion: if pre_parse: pre_parse(wd) @@ -195,8 +190,8 @@ def _git_parse_inner( out, _, ret = wd.do_ex(describe_command) else: out, _, ret = wd.default_describe() - distance: Optional[int] - node: Optional[str] + distance: int | None + node: str | None if ret == 0: tag, distance, node, dirty = _git_parse_describe(out) if distance == 0 and not dirty: @@ -226,7 +221,7 @@ def _git_parse_inner( ) -def _git_parse_describe(describe_output: str) -> Tuple[str, int, str, bool]: +def _git_parse_describe(describe_output: str) -> tuple[str, int, str, bool]: # 'describe_output' looks e.g. like 'v1.5.0-0-g4060507' or # 'v1.15.1rc1-37-g9bd1298-dirty'. @@ -240,7 +235,7 @@ def _git_parse_describe(describe_output: str) -> Tuple[str, int, str, bool]: return tag, int(number), node, dirty -def search_parent(dirname: _t.PathT) -> Optional[GitWorkdir]: +def search_parent(dirname: _t.PathT) -> GitWorkdir | None: """ Walk up the path to find the `.git` directory. :param dirname: Directory from which to start searching. @@ -269,7 +264,7 @@ def search_parent(dirname: _t.PathT) -> Optional[GitWorkdir]: def archival_to_version( - data: Dict[str, str], config: Optional[Configuration] = None + data: dict[str, str], config: Configuration | None = None ) -> ScmVersion: trace("data", data) archival_describe = data.get("describe-name", DESCRIBE_UNSUPPORTED) @@ -291,8 +286,8 @@ def archival_to_version( def parse_archival( - root: _t.PathT, config: Optional[Configuration] = None -) -> Optional[ScmVersion]: + root: _t.PathT, config: Configuration | None = None +) -> ScmVersion | None: archival = os.path.join(root, ".git_archival.txt") data = data_from_mime(archival) return archival_to_version(data, config=config) diff --git a/src/setuptools_scm/hacks.py b/src/setuptools_scm/hacks.py index 259bab2..494691d 100644 --- a/src/setuptools_scm/hacks.py +++ b/src/setuptools_scm/hacks.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import os -from typing import Optional from . import _types as _t from .config import Configuration @@ -13,8 +14,8 @@ _UNKNOWN = "UNKNOWN" def parse_pkginfo( - root: _t.PathT, config: Optional[Configuration] = None -) -> Optional[ScmVersion]: + root: _t.PathT, config: Configuration | None = None +) -> ScmVersion | None: pkginfo = os.path.join(root, "PKG-INFO") trace("pkginfo", pkginfo) @@ -27,8 +28,8 @@ def parse_pkginfo( def parse_pip_egg_info( - root: _t.PathT, config: Optional[Configuration] = None -) -> Optional[ScmVersion]: + root: _t.PathT, config: Configuration | None = None +) -> ScmVersion | None: pipdir = os.path.join(root, "pip-egg-info") if not os.path.isdir(pipdir): return None @@ -39,7 +40,7 @@ def parse_pip_egg_info( return parse_pkginfo(os.path.join(pipdir, items[0]), config=config) -def fallback_version(root: _t.PathT, config: Configuration) -> Optional[ScmVersion]: +def fallback_version(root: _t.PathT, config: Configuration) -> ScmVersion | None: if config.parentdir_prefix_version is not None: _, parent_name = os.path.split(os.path.abspath(root)) if parent_name.startswith(config.parentdir_prefix_version): diff --git a/src/setuptools_scm/hg.py b/src/setuptools_scm/hg.py index fad874b..fb31066 100644 --- a/src/setuptools_scm/hg.py +++ b/src/setuptools_scm/hg.py @@ -1,8 +1,8 @@ +from __future__ import annotations + import datetime import os from pathlib import Path -from typing import Dict -from typing import Optional from . import _types as _t from ._version_cls import Version @@ -22,14 +22,14 @@ class HgWorkdir(Workdir): COMMAND = "hg" @classmethod - def from_potential_worktree(cls, wd: _t.PathT) -> "HgWorkdir | None": + def from_potential_worktree(cls, wd: _t.PathT) -> HgWorkdir | None: require_command(cls.COMMAND) root, err, ret = do_ex("hg root", wd) if ret: return None return cls(root) - def get_meta(self, config: Configuration) -> Optional[ScmVersion]: + def get_meta(self, config: Configuration) -> ScmVersion | None: node: str tags_str: str @@ -107,7 +107,7 @@ class HgWorkdir(Workdir): cmd = ["hg", "log", "-r", revset, "-T", template] return self.do(cmd) - def get_latest_normalizable_tag(self) -> Optional[str]: + def get_latest_normalizable_tag(self) -> str | None: # Gets all tags containing a '.' (see #229) from oldest to newest outlines = self.hg_log( revset="ancestors(.) and tag('re:\\.')", @@ -124,7 +124,7 @@ class HgWorkdir(Workdir): out = self.hg_log(revset, ".") return len(out) - 1 - def check_changes_since_tag(self, tag: Optional[str]) -> bool: + def check_changes_since_tag(self, tag: str | None) -> bool: if tag == "0.0" or tag is None: return True @@ -140,7 +140,7 @@ class HgWorkdir(Workdir): return bool(self.hg_log(revset, ".")) -def parse(root: _t.PathT, config: "Configuration|None" = None) -> Optional[ScmVersion]: +def parse(root: _t.PathT, config: Configuration | None = None) -> ScmVersion | None: if not config: config = Configuration(root=root) @@ -167,7 +167,7 @@ def parse(root: _t.PathT, config: "Configuration|None" = None) -> Optional[ScmVe def archival_to_version( - data: Dict[str, str], config: "Configuration | None" = None + data: dict[str, str], config: Configuration | None = None ) -> ScmVersion: trace("data", data) node = data.get("node", "")[:12] @@ -186,9 +186,7 @@ def archival_to_version( return meta("0.0", node=node, config=config) -def parse_archival( - root: _t.PathT, config: Optional[Configuration] = None -) -> ScmVersion: +def parse_archival(root: _t.PathT, config: Configuration | None = None) -> ScmVersion: archival = os.path.join(root, ".hg_archival.txt") data = data_from_mime(archival) return archival_to_version(data, config=config) diff --git a/src/setuptools_scm/hg_git.py b/src/setuptools_scm/hg_git.py index be84367..28c5a36 100644 --- a/src/setuptools_scm/hg_git.py +++ b/src/setuptools_scm/hg_git.py @@ -1,9 +1,8 @@ +from __future__ import annotations + import os from datetime import date from datetime import datetime -from typing import Dict -from typing import Optional -from typing import Set from . import _types as _t from .git import GitWorkdir @@ -20,7 +19,7 @@ class GitWorkdirHgClient(GitWorkdir, HgWorkdir): COMMAND = "hg" @classmethod - def from_potential_worktree(cls, wd: _t.PathT) -> "GitWorkdirHgClient | None": + def from_potential_worktree(cls, wd: _t.PathT) -> GitWorkdirHgClient | None: require_command(cls.COMMAND) root, _, ret = do_ex("hg root", wd) if ret: @@ -31,14 +30,14 @@ class GitWorkdirHgClient(GitWorkdir, HgWorkdir): out, _, _ = self.do_ex("hg id -T '{dirty}'") return bool(out) - def get_branch(self) -> Optional[str]: + def get_branch(self) -> str | None: res = self.do_ex("hg id -T {bookmarks}") if res.returncode: trace("branch err", res) return None return res.out - def get_head_date(self) -> Optional[date]: + def get_head_date(self) -> date | None: date_part, err, ret = self.do_ex("hg log -r . -T {shortdate(date)}") if ret: trace("head date err", date_part, err, ret) @@ -51,14 +50,14 @@ class GitWorkdirHgClient(GitWorkdir, HgWorkdir): def fetch_shallow(self) -> None: pass - def get_hg_node(self) -> "str | None": + def get_hg_node(self) -> str | None: node, _, ret = self.do_ex("hg log -r . -T {node}") if not ret: return node else: return None - def _hg2git(self, hg_node: str) -> "str | None": + def _hg2git(self, hg_node: str) -> str | None: git_node = None with open(os.path.join(self.path, ".hg/git-mapfile")) as file: for line in file: @@ -67,7 +66,7 @@ class GitWorkdirHgClient(GitWorkdir, HgWorkdir): break return git_node - def node(self) -> "str | None": + def node(self) -> str | None: hg_node = self.get_hg_node() if hg_node is None: return None @@ -113,18 +112,18 @@ class GitWorkdirHgClient(GitWorkdir, HgWorkdir): ) if ret: return _FAKE_GIT_DESCRIBE_ERROR - hg_tags: Set[str] = set(hg_tags_str.split()) + hg_tags: set[str] = set(hg_tags_str.split()) if not hg_tags: return _FAKE_GIT_DESCRIBE_ERROR - node: "str | None" = None + node: str | None = None with open(os.path.join(self.path, ".hg/git-tags")) as fp: - git_tags: Dict[str, str] = dict(line.split() for line in fp) + git_tags: dict[str, str] = dict(line.split() for line in fp) - tag: "str | None" = next( + tag: str | None = next( # find the first hg tag which is also a git tag (tag for tag in hg_tags if tag in git_tags), None, diff --git a/src/setuptools_scm/integration.py b/src/setuptools_scm/integration.py index 53df404..1fddc53 100644 --- a/src/setuptools_scm/integration.py +++ b/src/setuptools_scm/integration.py @@ -1,9 +1,9 @@ +from __future__ import annotations + import os import warnings from typing import Any from typing import Callable -from typing import Dict -from typing import List import setuptools @@ -62,7 +62,7 @@ def _assign_version(dist: setuptools.Distribution, config: Configuration) -> Non def version_keyword( dist: setuptools.Distribution, keyword: str, - value: "bool | Dict[str, Any] | Callable[[], Dict[str, Any]]", + value: bool | dict[str, Any] | Callable[[], dict[str, Any]], ) -> None: if not value: return @@ -85,7 +85,7 @@ def version_keyword( _assign_version(dist, config) -def find_files(path: _t.PathT = "") -> List[str]: +def find_files(path: _t.PathT = "") -> list[str]: for ep in iter_entry_points("setuptools_scm.files_command"): command = ep.load() if isinstance(command, str): diff --git a/src/setuptools_scm/scm_workdir.py b/src/setuptools_scm/scm_workdir.py index 2d5dc17..45ab722 100644 --- a/src/setuptools_scm/scm_workdir.py +++ b/src/setuptools_scm/scm_workdir.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import ClassVar from . import _types as _t diff --git a/src/setuptools_scm/utils.py b/src/setuptools_scm/utils.py index 73a988c..d1a02fc 100644 --- a/src/setuptools_scm/utils.py +++ b/src/setuptools_scm/utils.py @@ -1,6 +1,8 @@ """ utils """ +from __future__ import annotations + import inspect import os import platform @@ -8,12 +10,8 @@ import shlex import subprocess import sys import warnings -from os import _Environ -from typing import Dict from typing import Iterator -from typing import List -from typing import Optional -from typing import Union +from typing import Mapping from . import _types as _t @@ -21,7 +19,7 @@ DEBUG = bool(os.environ.get("SETUPTOOLS_SCM_DEBUG")) IS_WINDOWS = platform.system() == "Windows" -def no_git_env(env: Union[Dict[str, str], _Environ[str]]) -> Dict[str, str]: +def no_git_env(env: Mapping[str, str]) -> dict[str, str]: # adapted from pre-commit # Too many bugs dealing with environment variables and GIT: # https://github.com/pre-commit/pre-commit/issues/300 @@ -47,7 +45,7 @@ def trace(*k: object) -> None: print(*k, file=sys.stderr, flush=True) -def ensure_stripped_str(str_or_bytes: "str | bytes") -> str: +def ensure_stripped_str(str_or_bytes: str | bytes) -> str: if isinstance(str_or_bytes, str): return str_or_bytes.strip() else: @@ -90,14 +88,14 @@ def do_ex(cmd: _t.CMD_TYPE, cwd: _t.PathT = ".") -> _t.CmdResult: ) -def do(cmd: "List[str] | str", cwd: "str | _t.PathT" = ".") -> str: +def do(cmd: list[str] | str, cwd: str | _t.PathT = ".") -> str: out, err, ret = do_ex(cmd, cwd) if ret: print(err) return out -def data_from_mime(path: _t.PathT) -> Dict[str, str]: +def data_from_mime(path: _t.PathT) -> dict[str, str]: with open(path, encoding="utf-8") as fp: content = fp.read() trace("content", repr(content)) @@ -115,7 +113,7 @@ def function_has_arg(fn: object, argname: str) -> bool: return argname in argspec -def has_command(name: str, args: "List[str] | None" = None, warn: bool = True) -> bool: +def has_command(name: str, args: list[str] | None = None, warn: bool = True) -> bool: try: cmd = [name, "help"] if args is None else [name, *args] p = _popen_pipes(cmd, ".") @@ -136,7 +134,7 @@ def require_command(name: str) -> None: def iter_entry_points( - group: str, name: Optional[str] = None + group: str, name: str | None = None ) -> Iterator[_t.EntrypointProtocol]: from ._entrypoints import iter_entry_points diff --git a/src/setuptools_scm/version.py b/src/setuptools_scm/version.py index f779664..4938d2a 100644 --- a/src/setuptools_scm/version.py +++ b/src/setuptools_scm/version.py @@ -1,4 +1,4 @@ -from __future__ import annotations # type: ignore +from __future__ import annotations import os import re diff --git a/testing/check_self_install.py b/testing/check_self_install.py index 6a32687..0cfab33 100644 --- a/testing/check_self_install.py +++ b/testing/check_self_install.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pkg_resources import setuptools_scm diff --git a/testing/conftest.py b/testing/conftest.py index ab9b641..89f124d 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -1,9 +1,9 @@ +from __future__ import annotations + import os from pathlib import Path from typing import Any from typing import Generator -from typing import List -from typing import Tuple import pytest @@ -16,7 +16,7 @@ os.environ["SETUPTOOLS_SCM_DEBUG"] = "1" VERSION_PKGS = ["setuptools", "setuptools_scm"] -def pytest_report_header() -> List[str]: +def pytest_report_header() -> list[str]: try: from importlib.metadata import version # type: ignore except ImportError: @@ -53,7 +53,7 @@ def wd(tmp_path: Path) -> WorkDir: @pytest.fixture -def repositories_hg_git(tmp_path: Path) -> Tuple[WorkDir, WorkDir]: +def repositories_hg_git(tmp_path: Path) -> tuple[WorkDir, WorkDir]: from setuptools_scm.utils import do tmp_path = tmp_path.resolve() diff --git a/testing/test_basic_api.py b/testing/test_basic_api.py index ef79fca..ba11a23 100644 --- a/testing/test_basic_api.py +++ b/testing/test_basic_api.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import shutil import sys diff --git a/testing/test_config.py b/testing/test_config.py index 53c034a..d7aa3f4 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re import textwrap from pathlib import Path diff --git a/testing/test_file_finder.py b/testing/test_file_finder.py index ec23349..a730434 100644 --- a/testing/test_file_finder.py +++ b/testing/test_file_finder.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import os import sys from typing import Generator from typing import Iterable -from typing import Set import pytest @@ -44,7 +45,7 @@ def inwd( yield wd -def _sep(paths: Iterable[str]) -> Set[str]: +def _sep(paths: Iterable[str]) -> set[str]: return {path.replace("/", os.path.sep) for path in paths} diff --git a/testing/test_functions.py b/testing/test_functions.py index fc62b5f..53bc92b 100644 --- a/testing/test_functions.py +++ b/testing/test_functions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pathlib import Path import pytest diff --git a/testing/test_git.py b/testing/test_git.py index 27bccce..8394f7a 100644 --- a/testing/test_git.py +++ b/testing/test_git.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import sys from datetime import date @@ -6,7 +8,6 @@ from datetime import timezone from os.path import join as opj from pathlib import Path from textwrap import dedent -from typing import Dict from unittest.mock import Mock from unittest.mock import patch @@ -144,7 +145,7 @@ def test_version_from_git(wd: WorkDir) -> None: ) -setup_py_with_normalize: Dict[str, str] = { +setup_py_with_normalize: dict[str, str] = { "false": """ from setuptools import setup setup(use_scm_version={'normalize': False, 'write_to': 'VERSION.txt'}) @@ -475,7 +476,7 @@ def test_git_getdate_signed_commit(signed_commit_wd: WorkDir) -> None: ], ) @pytest.mark.filterwarnings("ignore:git archive did not support describe output") -def test_git_archival_to_version(expected: str, from_data: Dict[str, str]) -> None: +def test_git_archival_to_version(expected: str, from_data: dict[str, str]) -> None: config = Configuration() version = archival_to_version(from_data, config=config) assert ( diff --git a/testing/test_hg_git.py b/testing/test_hg_git.py index 1271b72..cf64bbe 100644 --- a/testing/test_hg_git.py +++ b/testing/test_hg_git.py @@ -1,4 +1,4 @@ -from typing import Tuple +from __future__ import annotations import pytest @@ -23,7 +23,7 @@ def _check_hg_git() -> None: pytest.skip("hg-git not installed") -def test_base(repositories_hg_git: Tuple[WorkDir, WorkDir]) -> None: +def test_base(repositories_hg_git: tuple[WorkDir, WorkDir]) -> None: wd, wd_git = repositories_hg_git assert wd_git.version == "0.1.dev0" diff --git a/testing/test_integration.py b/testing/test_integration.py index 9759fa8..25a0469 100644 --- a/testing/test_integration.py +++ b/testing/test_integration.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import sys import textwrap diff --git a/testing/test_main.py b/testing/test_main.py index 41588bb..10d78c8 100644 --- a/testing/test_main.py +++ b/testing/test_main.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os.path import sys import textwrap diff --git a/testing/test_mercurial.py b/testing/test_mercurial.py index 0b77e37..5e0bc02 100644 --- a/testing/test_mercurial.py +++ b/testing/test_mercurial.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import os from pathlib import Path -from typing import Dict import pytest @@ -40,7 +41,7 @@ archival_mapping = { @pytest.mark.parametrize("expected,data", sorted(archival_mapping.items())) -def test_archival_to_version(expected: str, data: Dict[str, str]) -> None: +def test_archival_to_version(expected: str, data: dict[str, str]) -> None: config = Configuration() version = archival_to_version(data, config=config) assert ( diff --git a/testing/test_regressions.py b/testing/test_regressions.py index c716857..6de7141 100644 --- a/testing/test_regressions.py +++ b/testing/test_regressions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import subprocess import sys diff --git a/testing/test_setuptools_support.py b/testing/test_setuptools_support.py index f695452..212b481 100644 --- a/testing/test_setuptools_support.py +++ b/testing/test_setuptools_support.py @@ -1,13 +1,14 @@ """ integration tests that check setuptools version support """ +from __future__ import annotations + import os import pathlib import subprocess import sys from typing import Any from typing import Callable -from typing import List import _pytest.config import pytest @@ -182,7 +183,7 @@ def test_on_old_setuptools( # monkeypatch.delenv("SETUPTOOLS_SCM_DEBUG", raising=False) - def run_and_output(cmd: "List[str | pathlib.Path]") -> bytes: + def run_and_output(cmd: list[str | pathlib.Path]) -> bytes: res = subprocess.run(cmd, cwd=str(pkg), stdout=subprocess.PIPE) if not res.returncode: return res.stdout.strip() diff --git a/testing/test_version.py b/testing/test_version.py index aecceb6..0a07095 100644 --- a/testing/test_version.py +++ b/testing/test_version.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from datetime import date from datetime import timedelta from typing import Any @@ -222,7 +224,7 @@ def test_format_version_schemes() -> None: def date_to_str( - date_: "date | None" = None, + date_: date | None = None, days_offset: int = 0, fmt: str = "{dt:%y}.{dt.month}.{dt.day}", ) -> str: diff --git a/testing/wd_wrapper.py b/testing/wd_wrapper.py index 3fbdd1d..de578c4 100644 --- a/testing/wd_wrapper.py +++ b/testing/wd_wrapper.py @@ -1,7 +1,8 @@ +from __future__ import annotations + import itertools from pathlib import Path from typing import Any -from typing import List class WorkDir: @@ -18,7 +19,7 @@ class WorkDir: self.cwd = cwd self.__counter = itertools.count() - def __call__(self, cmd: "List[str] | str", **kw: object) -> str: + def __call__(self, cmd: list[str] | str, **kw: object) -> str: if kw: assert isinstance(cmd, str), "formatting the command requires text input" cmd = cmd.format(**kw) @@ -26,7 +27,7 @@ class WorkDir: return do(cmd, self.cwd) - def write(self, name: str, content: "str | bytes", **kw: object) -> Path: + def write(self, name: str, content: str | bytes, **kw: object) -> Path: path = self.cwd / name if kw: assert isinstance(content, str) @@ -37,28 +38,26 @@ class WorkDir: path.write_text(content) return path - def _reason(self, given_reason: "str | None") -> str: + def _reason(self, given_reason: str | None) -> str: if given_reason is None: return f"number-{next(self.__counter)}" else: return given_reason def add_and_commit( - self, reason: "str | None" = None, signed: bool = False, **kwargs: object + self, reason: str | None = None, signed: bool = False, **kwargs: object ) -> None: self(self.add_command) self.commit(reason=reason, signed=signed, **kwargs) - def commit(self, reason: "str | None" = None, signed: bool = False) -> None: + def commit(self, reason: str | None = None, signed: bool = False) -> None: reason = self._reason(reason) self( self.commit_command if not signed else self.signed_commit_command, reason=reason, ) - def commit_testfile( - self, reason: "str | None" = None, signed: bool = False - ) -> None: + def commit_testfile(self, reason: str | None = None, signed: bool = False) -> None: reason = self._reason(reason) self.write("test.txt", "test {reason}", reason=reason) self(self.add_command) |