Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: tox-dev/tox
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4.2.5
Choose a base ref
...
head repository: tox-dev/tox
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4.2.6
Choose a head ref
  • 2 commits
  • 5 files changed
  • 2 contributors

Commits on Jan 6, 2023

  1. Handle properly pip --no-binary / --only-binary options in requiremen…

    …ts.txt format files. (#2834)
    
    Fixes #2814
    q0w authored Jan 6, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    e9d6e63 View commit details
  2. release 4.2.6

    gaborbernat committed Jan 6, 2023
    Copy the full SHA
    fd866d5 View commit details
8 changes: 8 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -4,6 +4,14 @@ Release History

.. towncrier release notes start
v4.2.6 (2023-01-06)
-------------------

Bugfixes - 4.2.6
~~~~~~~~~~~~~~~~
- Handle properly pip ``--no-binary`` / ``--only-binary`` options in requirements.txt format files. (:issue:`2814`)


v4.2.5 (2023-01-06)
-------------------

4 changes: 2 additions & 2 deletions src/tox/tox_env/python/pip/req/args.py
Original file line number Diff line number Diff line change
@@ -33,8 +33,8 @@ def _global_options(parser: ArgumentParser) -> None:
parser.add_argument("-r", "--requirement", action=AddUniqueAction, dest="requirements")
parser.add_argument("-e", "--editable", action=AddUniqueAction, dest="editables")
parser.add_argument("-f", "--find-links", action=AddUniqueAction)
parser.add_argument("--no-binary", choices=[":all:", ":none:"]) # TODO: colon separated package names
parser.add_argument("--only-binary", choices=[":all:", ":none:"]) # TODO: colon separated package names
parser.add_argument("--no-binary")
parser.add_argument("--only-binary")
parser.add_argument("--prefer-binary", action="store_true", default=False)
parser.add_argument("--require-hashes", action="store_true", default=False)
parser.add_argument("--pre", action="store_true", default=False)
13 changes: 10 additions & 3 deletions src/tox/tox_env/python/pip/req/file.py
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
from packaging.requirements import InvalidRequirement, Requirement

from .args import build_parser
from .util import VCS, get_url_scheme, is_url, url_to_path
from .util import VCS, get_url_scheme, handle_binary_option, is_url, url_to_path

# Matches environment variable-style values in '${MY_VARIABLE_1}' with the variable name consisting of only uppercase
# letters, digits or the '_' (underscore). This follows the POSIX standard defined in IEEE Std 1003.1, 2013 Edition.
@@ -341,10 +341,17 @@ def _merge_option_line(self, base_opt: Namespace, opt: Namespace, filename: str)
base_opt.trusted_hosts = []
if host not in base_opt.trusted_hosts:
base_opt.trusted_hosts.append(host)

no_binary = base_opt.no_binary if hasattr(base_opt, "no_binary") else set()
only_binary = base_opt.only_binary if hasattr(base_opt, "only_binary") else set()
if opt.no_binary:
base_opt.no_binary = opt.no_binary
handle_binary_option(opt.no_binary, no_binary, only_binary)
if opt.only_binary:
base_opt.only_binary = opt.only_binary
handle_binary_option(opt.only_binary, only_binary, no_binary)
if no_binary:
base_opt.no_binary = no_binary
if only_binary:
base_opt.only_binary = only_binary

@staticmethod
def _break_args_options(line: str) -> tuple[str, str]:
20 changes: 20 additions & 0 deletions src/tox/tox_env/python/pip/req/util.py
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@
from urllib.parse import urlsplit
from urllib.request import url2pathname

from packaging.utils import canonicalize_name

VCS = ["ftp", "ssh", "git", "hg", "bzr", "sftp", "svn"]
VALID_SCHEMAS = ["http", "https", "file"] + VCS

@@ -26,3 +28,21 @@ def url_to_path(url: str) -> str:
raise ValueError(f"non-local file URIs are not supported on this platform: {url!r}")
path = url2pathname(netloc + path)
return path


def handle_binary_option(value: str, target: set[str], other: set[str]) -> None:
new = value.split(",")
while ":all:" in new:
other.clear()
target.clear()
target.add(":all:")
del new[: new.index(":all:") + 1]
if ":none:" not in new:
return
for name in new:
if name == ":none:":
target.clear()
continue
name = canonicalize_name(name)
other.discard(name)
target.add(name)
39 changes: 33 additions & 6 deletions tests/tox_env/python/pip/req/test_file.py
Original file line number Diff line number Diff line change
@@ -140,16 +140,43 @@
["--use-feature", "2020-resolver", "--use-feature", "fast-deps"],
id="use-feature multiple duplicate different line",
),
pytest.param("--no-binary :all:", {"no_binary": ":all:"}, [], ["--no-binary", ":all:"], id="no-binary all"),
pytest.param("--no-binary :none:", {"no_binary": ":none:"}, [], ["--no-binary", ":none:"], id="no-binary none"),
pytest.param("--only-binary :all:", {"only_binary": ":all:"}, [], ["--only-binary", ":all:"], id="only-binary all"),
pytest.param("--no-binary :all:", {"no_binary": {":all:"}}, [], ["--no-binary", {":all:"}], id="no-binary all"),
pytest.param("--no-binary :none:", {"no_binary": {":none:"}}, [], [], id="no-binary none"),
pytest.param(
"--only-binary :all:",
{"only_binary": {":all:"}},
[],
["--only-binary", {":all:"}],
id="only-binary all",
),
pytest.param(
"--only-binary :none:",
{"only_binary": ":none:"},
{"only_binary": {":none:"}},
[],
[],
["--only-binary", ":none:"],
id="only-binary none",
),
pytest.param(
"--no-binary=foo --only-binary=foo",
{"only_binary": {"foo"}},
[],
["--only-binary", {"foo"}],
id="no-binary-and-only-binary",
),
pytest.param(
"--no-binary=foo --no-binary=:none:",
{},
[],
[],
id="no-binary-none-last",
),
pytest.param(
"--only-binary=:none: --no-binary=foo",
{"no_binary": {"foo"}},
[],
["--no-binary", {"foo"}],
id="no-binary-none-first",
),
pytest.param("####### example-requirements.txt #######", {}, [], [], id="comment"),
pytest.param("\t##### Requirements without Version Specifiers ######", {}, [], [], id="tab and comment"),
pytest.param(" # start", {}, [], [], id="space and comment"),
@@ -289,7 +316,7 @@ def test_req_file(tmp_path: Path, req: str, opts: dict[str, Any], requirements:
req_file = RequirementsFile(requirements_txt, constraint=False)
assert req_file.as_root_args == as_args
assert str(req_file) == f"-r {requirements_txt}"
assert vars(req_file.options) == opts
assert vars(req_file.options) == (opts if {":none:"} not in opts.values() else {})
found = [str(i) for i in req_file.requirements]
assert found == requirements