-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Upgrade configuration syntax to v4 (#146)
- Loading branch information
1 parent
792e559
commit 9aac31d
Showing
15 changed files
with
303 additions
and
136 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,36 @@ | ||
from __future__ import annotations | ||
|
||
import re | ||
from packaging.requirements import InvalidRequirement, Requirement | ||
|
||
BASE_NAME_REGEX = re.compile(r"[^!=><~\s@]+") | ||
REQ_REGEX = re.compile(r"(===|==|!=|~=|>=?|<=?|@)\s*([^,]+)") | ||
|
||
def normalize_req(req: str) -> str: | ||
try: | ||
parsed = Requirement(req) | ||
except InvalidRequirement: | ||
return req | ||
|
||
for spec in parsed.specifier: | ||
if spec.operator in (">=", "=="): | ||
version = spec.version | ||
while version.endswith(".0"): | ||
version = version[:-2] | ||
spec._spec = (spec._spec[0], version) | ||
return str(parsed) | ||
|
||
|
||
def _req_name(req: str) -> str: | ||
try: | ||
return Requirement(req).name | ||
except InvalidRequirement: | ||
return req | ||
|
||
|
||
def requires(raws: list[str]) -> list[str]: | ||
values = (_normalize_req(req) for req in raws if req) | ||
normalized = sorted(values, key=lambda req: (";" in req, _req_base(req), req)) | ||
values = (normalize_req(req) for req in raws if req) | ||
normalized = sorted(values, key=lambda req: (";" in req, _req_name(req), req)) | ||
return normalized | ||
|
||
|
||
def _normalize_req(req: str) -> str: | ||
lib, _, envs = req.partition(";") | ||
normalized = _normalize_lib(lib) | ||
envs = envs.strip() | ||
if not envs: | ||
return normalized | ||
return f"{normalized};{envs}" | ||
|
||
|
||
def _normalize_lib(lib: str) -> str: | ||
base = _req_base(lib) | ||
values = sorted( | ||
(f"{m.group(1)}{m.group(2)}" for m in REQ_REGEX.finditer(lib)), | ||
key=lambda c: ("<" in c, ">" in "c", c), | ||
) | ||
if values: # strip .0 version | ||
while values[0].endswith(".0") and (values[0].startswith(">=") or values[0].startswith("==")): | ||
values[0] = values[0][:-2] | ||
return f"{base}{','.join(values)}" | ||
|
||
|
||
def _req_base(lib: str) -> str: | ||
match = re.match(BASE_NAME_REGEX, lib) | ||
if match is None: | ||
raise ValueError(repr(lib)) | ||
return match.group(0) | ||
__all__ = [ | ||
"requires", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,67 @@ | ||
from __future__ import annotations | ||
|
||
from configparser import ConfigParser | ||
from configparser import ConfigParser, SectionProxy | ||
from functools import partial | ||
from typing import Callable, Mapping | ||
|
||
from .util import fix_and_reorder, to_boolean, to_list_of_env_values, to_py_dependencies | ||
from packaging.requirements import Requirement | ||
from packaging.version import Version | ||
|
||
from .requires import requires | ||
from .util import collect_multi_line, fix_and_reorder, to_boolean, to_list_of_env_values, to_py_dependencies | ||
|
||
|
||
def format_tox_section(parser: ConfigParser, pin_toxenvs: list[str]) -> None: | ||
if not parser.has_section("tox"): | ||
return | ||
parser.add_section("tox") | ||
tox = parser["tox"] | ||
_handle_min_version(tox) | ||
tox.pop("isolated_build", None) | ||
|
||
tox_section_cfg: Mapping[str, Callable[[str], str]] = { | ||
"minversion": str, | ||
"min_version": str, | ||
"requires": to_py_dependencies, | ||
"provision_tox_env": str, | ||
"env_list": partial(to_list_of_env_values, pin_toxenvs), | ||
"envlist": partial(to_list_of_env_values, pin_toxenvs), | ||
"isolated_build": to_boolean, | ||
"package_env": str, | ||
"isolated_build_env": str, | ||
"no_package": to_boolean, | ||
"skipsdist": to_boolean, | ||
"skip_missing_interpreters": to_boolean, | ||
"ignore_base_python_conflict": to_boolean, | ||
"ignore_basepython_conflict": to_boolean, | ||
} | ||
fix_and_reorder(parser, "tox", tox_section_cfg) | ||
upgrade = { | ||
"envlist": "env_list", | ||
"toxinidir": "tox_root", | ||
"toxworkdir": "work_dir", | ||
"skipsdist": "no_package", | ||
"isolated_build_env": "package_env", | ||
"setupdir": "package_root", | ||
"ignore_basepython_conflict": "ignore_base_python_conflict", | ||
} | ||
fix_and_reorder(parser, "tox", tox_section_cfg, upgrade) | ||
|
||
|
||
def _handle_min_version(tox: SectionProxy) -> None: | ||
min_version = next((tox.pop(i) for i in ("minversion", "min_version") if i in tox), None) | ||
if min_version is None or int(min_version.split(".")[0]) < 4: | ||
min_version = "4.2" | ||
tox_requires = [ | ||
Requirement(i) | ||
for i in collect_multi_line( | ||
tox.get("requires", ""), | ||
line_split=None, | ||
normalize=lambda groups: {k: requires(v) for k, v in groups.items()}, | ||
)[0] | ||
] | ||
for _at, entry in enumerate(tox_requires): | ||
if entry.name == "tox": | ||
break | ||
else: | ||
_at = -1 | ||
if _at == -1: | ||
tox_requires.append(Requirement(f"tox>={min_version}")) | ||
else: | ||
specifiers = list(tox_requires[_at].specifier) | ||
if len(specifiers) == 0 or Version(specifiers[0].version) < Version(min_version): | ||
tox_requires[_at] = Requirement(f"tox>={min_version}") | ||
tox["requires"] = "\n".join(str(i) for i in tox_requires) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.