Repository: tox-dev/tox

Issue:
tox4: pip options support in requirements.txt
Version: tox 4.0.0a4

The requirements.txt format supports pip options, as documented here: https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format

But using the option crashes tox4. This worked in tox 3.

To reproduce:

```console
$ git clone https://github.com/pypa/pip.git
$ cd pip
$ tox4 legacy -e py38
py38: internal error
Traceback (most recent call last):
  File "lib/python3.9/site-packages/tox/session/cmd/run/single.py", line 41, in _evaluate
    tox_env.ensure_setup(recreate=recreate)
  File "lib/python3.9/site-packages/tox/tox_env/api.py", line 167, in ensure_setup
    self.setup()
  File "lib/python3.9/site-packages/tox/tox_env/python/runner.py", line 46, in setup
    self.install_deps()
  File "lib/python3.9/site-packages/tox/tox_env/python/runner.py", line 70, in install_deps
    requirement_file_content = requirements_file.validate_and_expand()
  File "lib/python3.9/site-packages/tox/tox_env/python/req_file.py", line 126, in validate_and_expand
    result.extend(req_file.validate_and_expand())
  File "lib/python3.9/site-packages/tox/tox_env/python/req_file.py", line 130, in validate_and_expand
    raise ValueError(line)
ValueError: --use-feature=2020-resolver
py38: FAIL ✖ in 0.06 seconds
  py38: FAIL code 2 (0.06 seconds)
  evaluation failed :( (0.10 seconds)
```

<details>
 <summary>Full log (anonymised)</summary>

```
ROOT: 221 D setup logging to DEBUG on pid 27538 [tox/report.py:211]
ROOT: 236 W remove tox env folder $project_root/.tox/4/py38 [tox/tox_env/api.py:190]
ROOT: 339 I find interpreter for spec PythonSpec(implementation=CPython, major=3, minor=8) [virtualenv/discovery/builtin.py:62]
ROOT: 339 D discover exe for PythonInfo(spec=CPython3.9.0.final.0-64, exe=$tox_prefix/bin/python, platform=darwin, version='3.9.0 (default, Nov 21 2020, 22:02:08) \n[Clang 12.0.0 (clang-1200.0.32.21)]', encoding_fs_io=utf-8-utf-8) in $sys_prefix [virtualenv/discovery/py_info.py:371]
ROOT: 340 D filesystem is case-sensitive [virtualenv/info.py:28]
ROOT: 342 D Attempting to acquire lock 4490835328 on $libdir/virtualenv/py_info/1/0dd39cadf38d642f262c45befae072f4eba5242a64fcd0af3712cb7000099054.lock [filelock.py:270]
ROOT: 342 D Lock 4490835328 acquired on $libdir/virtualenv/py_info/1/0dd39cadf38d642f262c45befae072f4eba5242a64fcd0af3712cb7000099054.lock [filelock.py:274]
ROOT: 343 D got python info of $sys_prefix/bin/python3.9 from $libdir/virtualenv/py_info/1/0dd39cadf38d642f262c45befae072f4eba5242a64fcd0af3712cb7000099054.json [virtualenv/app_data/via_disk_folder.py:135]
ROOT: 344 D Attempting to release lock 4490835328 on $libdir/virtualenv/py_info/1/0dd39cadf38d642f262c45befae072f4eba5242a64fcd0af3712cb7000099054.lock [filelock.py:315]
ROOT: 345 D Lock 4490835328 released on $libdir/virtualenv/py_info/1/0dd39cadf38d642f262c45befae072f4eba5242a64fcd0af3712cb7000099054.lock [filelock.py:318]
ROOT: 345 I proposed PythonInfo(spec=CPython3.9.0.final.0-64, system=$sys_prefix/bin/python3.9, exe=$tox_prefix/bin/python, platform=darwin, version='3.9.0 (default, Nov 21 2020, 22:02:08) \n[Clang 12.0.0 (clang-1200.0.32.21)]', encoding_fs_io=utf-8-utf-8) [virtualenv/discovery/builtin.py:68]
ROOT: 345 D discover PATH[0]=$path0 [virtualenv/discovery/builtin.py:112]
ROOT: 346 D Attempting to acquire lock 4490834272 on $libdir/virtualenv/py_info/1/72fa9ab46076656735501d364f18b4e0263de8642ccefb942f5c7ea68c4a2db8.lock [filelock.py:270]
ROOT: 346 D Lock 4490834272 acquired on $libdir/virtualenv/py_info/1/72fa9ab46076656735501d364f18b4e0263de8642ccefb942f5c7ea68c4a2db8.lock [filelock.py:274]
ROOT: 347 D got python info of $path0/python3 from $libdir/virtualenv/py_info/1/72fa9ab46076656735501d364f18b4e0263de8642ccefb942f5c7ea68c4a2db8.json [virtualenv/app_data/via_disk_folder.py:135]
ROOT: 348 D Attempting to release lock 4490834272 on $libdir/virtualenv/py_info/1/72fa9ab46076656735501d364f18b4e0263de8642ccefb942f5c7ea68c4a2db8.lock [filelock.py:315]
ROOT: 348 D Lock 4490834272 released on $libdir/virtualenv/py_info/1/72fa9ab46076656735501d364f18b4e0263de8642ccefb942f5c7ea68c4a2db8.lock [filelock.py:318]
ROOT: 348 I proposed PathPythonInfo(spec=CPython3.9.0.final.0-64, exe=$path0/python3, platform=darwin, version='3.9.0 (default, Nov 21 2020, 22:02:08) \n[Clang 12.0.0 (clang-1200.0.32.21)]', encoding_fs_io=utf-8-utf-8) [virtualenv/discovery/builtin.py:68]
ROOT: 349 D discover PATH[1]=$path1 [virtualenv/discovery/builtin.py:112]
ROOT: 350 D Attempting to acquire lock 4490799088 on $libdir/virtualenv/py_info/1/ab0e10762c764739f09e25a792a6b8e56c3af9d63a034ef7bb1b5fa032ef6b5d.lock [filelock.py:270]
ROOT: 350 D Lock 4490799088 acquired on $libdir/virtualenv/py_info/1/ab0e10762c764739f09e25a792a6b8e56c3af9d63a034ef7bb1b5fa032ef6b5d.lock [filelock.py:274]
ROOT: 350 D got python info of $path1/python3.8 from $libdir/virtualenv/py_info/1/ab0e10762c764739f09e25a792a6b8e56c3af9d63a034ef7bb1b5fa032ef6b5d.json [virtualenv/app_data/via_disk_folder.py:135]
ROOT: 351 D Attempting to release lock 4490799088 on $libdir/virtualenv/py_info/1/ab0e10762c764739f09e25a792a6b8e56c3af9d63a034ef7bb1b5fa032ef6b5d.lock [filelock.py:315]
ROOT: 351 D Lock 4490799088 released on $libdir/virtualenv/py_info/1/ab0e10762c764739f09e25a792a6b8e56c3af9d63a034ef7bb1b5fa032ef6b5d.lock [filelock.py:318]
ROOT: 352 I proposed PathPythonInfo(spec=CPython3.8.6.final.0-64, exe=$path1/python3.8, platform=darwin, version='3.8.6 (default, Oct 27 2020, 17:10:36) \n[Clang 12.0.0 (clang-1200.0.32.21)]', encoding_fs_io=utf-8-utf-8) [virtualenv/discovery/builtin.py:68]
ROOT: 352 D accepted PathPythonInfo(spec=CPython3.8.6.final.0-64, exe=$path1/python3.8, platform=darwin, version='3.8.6 (default, Oct 27 2020, 17:10:36) \n[Clang 12.0.0 (clang-1200.0.32.21)]', encoding_fs_io=utf-8-utf-8) [virtualenv/discovery/builtin.py:70]
ROOT: 422 I create virtual environment via CPython3Posix(dest=$project_root/.tox/4/py38, clear=True, no_vcs_ignore=False, global=False) [virtualenv/run/session.py:52]
ROOT: 422 D create folder $project_root/.tox/4/py38/bin [virtualenv/util/path/_sync.py:25]
ROOT: 423 D create folder $project_root/.tox/4/py38/lib/python3.8/site-packages [virtualenv/util/path/_sync.py:25]
ROOT: 423 D write $project_root/.tox/4/py38/pyvenv.cfg [virtualenv/create/pyenv_cfg.py:34]
ROOT: 423 D 	home = $sys_prefix [virtualenv/create/pyenv_cfg.py:38]
ROOT: 424 D 	implementation = CPython [virtualenv/create/pyenv_cfg.py:38]
ROOT: 424 D 	version_info = 3.8.6.final.0 [virtualenv/create/pyenv_cfg.py:38]
ROOT: 424 D 	virtualenv = 20.3.1 [virtualenv/create/pyenv_cfg.py:38]
ROOT: 424 D 	include-system-site-packages = false [virtualenv/create/pyenv_cfg.py:38]
ROOT: 424 D 	base-prefix = $sys_prefix [virtualenv/create/pyenv_cfg.py:38]
ROOT: 424 D 	base-exec-prefix = $sys_prefix [virtualenv/create/pyenv_cfg.py:38]
ROOT: 424 D 	base-executable = $path1/python3.8 [virtualenv/create/pyenv_cfg.py:38]
ROOT: 425 D symlink $path1/python3.8 to $project_root/.tox/4/py38/bin/python [virtualenv/util/path/_sync.py:44]
ROOT: 426 D create virtualenv import hook file $project_root/.tox/4/py38/lib/python3.8/site-packages/_virtualenv.pth [virtualenv/create/via_global_ref/api.py:95]
ROOT: 427 D create $project_root/.tox/4/py38/lib/python3.8/site-packages/_virtualenv.py [virtualenv/create/via_global_ref/api.py:98]
ROOT: 428 D ============================== target debug ============================== [virtualenv/run/session.py:54]
ROOT: 428 D debug via $project_root/.tox/4/py38/bin/python $tox_prefix/lib/python3.9/site-packages/virtualenv/create/debug.py [virtualenv/create/creator.py:223]
ROOT: 428 D {
  "sys": {
    "executable": "$project_root/.tox/4/py38/bin/python",
    "_base_executable": "$project_root/.tox/4/py38/bin/python",
    "prefix": "$project_root/.tox/4/py38",
    "base_prefix": "$sys_prefix",
    "real_prefix": null,
    "exec_prefix": "$project_root/.tox/4/py38",
    "base_exec_prefix": "$sys_prefix",
    "path": [
      "$sys_prefix/lib/python38.zip",
      "$sys_prefix/lib/python3.8",
      "$sys_prefix/lib/python3.8/lib-dynload",
      "$project_root/.tox/4/py38/lib/python3.8/site-packages"
    ],
    "meta_path": [
      "<class '_virtualenv._Finder'>",
      "<class '_frozen_importlib.BuiltinImporter'>",
      "<class '_frozen_importlib.FrozenImporter'>",
      "<class '_frozen_importlib_external.PathFinder'>"
    ],
    "fs_encoding": "utf-8",
    "io_encoding": "utf-8"
  },
  "version": "3.8.6 (default, Oct 27 2020, 17:10:36) \n[Clang 12.0.0 (clang-1200.0.32.21)]",
  "makefile_filename": "$sys_prefix/lib/python3.8/config-3.8-darwin/Makefile",
  "os": "<module 'os' from '$sys_prefix/lib/python3.8/os.py'>",
  "site": "<module 'site' from '$sys_prefix/lib/python3.8/site.py'>",
  "datetime": "<module 'datetime' from '$sys_prefix/lib/python3.8/datetime.py'>",
  "math": "<module 'math' from '$sys_prefix/lib/python3.8/lib-dynload/math.cpython-38-darwin.so'>",
  "json": "<module 'json' from '$sys_prefix/lib/python3.8/json/__init__.py'>"
} [virtualenv/run/session.py:55]
ROOT: 544 I add seed packages via FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=$libdir/virtualenv) [virtualenv/run/session.py:59]
py38: 549 D got embed update of distribution pip from $libdir/virtualenv/wheel/3.8/embed/1/pip.json [virtualenv/app_data/via_disk_folder.py:135]
py38: 550 D got embed update of distribution setuptools from $libdir/virtualenv/wheel/3.8/embed/1/setuptools.json [virtualenv/app_data/via_disk_folder.py:135]
py38: 555 D got embed update of distribution wheel from $libdir/virtualenv/wheel/3.8/embed/1/wheel.json [virtualenv/app_data/via_disk_folder.py:135]
py38: 556 D install pip from wheel $tox_prefix/lib/python3.9/site-packages/virtualenv/seed/wheels/embed/pip-20.3.3-py2.py3-none-any.whl via CopyPipInstall [virtualenv/seed/embed/via_app_data/via_app_data.py:49]
py38: 556 D install setuptools from wheel $tox_prefix/lib/python3.9/site-packages/virtualenv/seed/wheels/embed/setuptools-51.1.2-py3-none-any.whl via CopyPipInstall [virtualenv/seed/embed/via_app_data/via_app_data.py:49]
py38: 557 D install wheel from wheel $tox_prefix/lib/python3.9/site-packages/virtualenv/seed/wheels/embed/wheel-0.36.2-py2.py3-none-any.whl via CopyPipInstall [virtualenv/seed/embed/via_app_data/via_app_data.py:49]
py38: 558 D Attempting to acquire lock 4494292928 on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/pip-20.3.3-py2.py3-none-any.lock [filelock.py:270]
py38: 558 D Lock 4494292928 acquired on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/pip-20.3.3-py2.py3-none-any.lock [filelock.py:274]
py38: 559 D Attempting to acquire lock 4494293984 on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any.lock [filelock.py:270]
py38: 559 D Attempting to acquire lock 4494294560 on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any.lock [filelock.py:270]
py38: 559 D Lock 4494293984 acquired on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any.lock [filelock.py:274]
py38: 559 D Lock 4494294560 acquired on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any.lock [filelock.py:274]
py38: 559 D Attempting to release lock 4494292928 on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/pip-20.3.3-py2.py3-none-any.lock [filelock.py:315]
py38: 560 D Lock 4494292928 released on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/pip-20.3.3-py2.py3-none-any.lock [filelock.py:318]
py38: 560 D Attempting to release lock 4494293984 on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any.lock [filelock.py:315]
py38: 560 D Attempting to release lock 4494294560 on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any.lock [filelock.py:315]
py38: 560 D Lock 4494293984 released on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any.lock [filelock.py:318]
py38: 560 D Lock 4494294560 released on $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any.lock [filelock.py:318]
py38: 561 D copy $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/pip-20.3.3-py2.py3-none-any/pip-20.3.3.virtualenv to $project_root/.tox/4/py38/lib/python3.8/site-packages/pip-20.3.3.virtualenv [virtualenv/util/path/_sync.py:52]
py38: 561 D copy directory $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any/wheel-0.36.2.dist-info to $project_root/.tox/4/py38/lib/python3.8/site-packages/wheel-0.36.2.dist-info [virtualenv/util/path/_sync.py:52]
py38: 562 D copy $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any/setuptools-51.1.2.virtualenv to $project_root/.tox/4/py38/lib/python3.8/site-packages/setuptools-51.1.2.virtualenv [virtualenv/util/path/_sync.py:52]
py38: 563 D copy $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any/easy_install.py to $project_root/.tox/4/py38/lib/python3.8/site-packages/easy_install.py [virtualenv/util/path/_sync.py:52]
py38: 564 D copy directory $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any/setuptools-51.1.2.dist-info to $project_root/.tox/4/py38/lib/python3.8/site-packages/setuptools-51.1.2.dist-info [virtualenv/util/path/_sync.py:52]
py38: 564 D copy directory $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/pip-20.3.3-py2.py3-none-any/pip to $project_root/.tox/4/py38/lib/python3.8/site-packages/pip [virtualenv/util/path/_sync.py:52]
py38: 574 D copy directory $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any/wheel to $project_root/.tox/4/py38/lib/python3.8/site-packages/wheel [virtualenv/util/path/_sync.py:52]
py38: 576 D copy $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any/distutils-precedence.pth to $project_root/.tox/4/py38/lib/python3.8/site-packages/distutils-precedence.pth [virtualenv/util/path/_sync.py:52]
py38: 579 D copy directory $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any/setuptools to $project_root/.tox/4/py38/lib/python3.8/site-packages/setuptools [virtualenv/util/path/_sync.py:52]
py38: 603 D copy $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/wheel-0.36.2-py2.py3-none-any/wheel-0.36.2.virtualenv to $project_root/.tox/4/py38/lib/python3.8/site-packages/wheel-0.36.2.virtualenv [virtualenv/util/path/_sync.py:52]
py38: 608 D changing mode of $project_root/.tox/4/py38/bin/wheel3 to 755 [distlib/util.py:566]
py38: 609 D changing mode of $project_root/.tox/4/py38/bin/wheel3.8 to 755 [distlib/util.py:566]
py38: 610 D changing mode of $project_root/.tox/4/py38/bin/wheel-3.8 to 755 [distlib/util.py:566]
py38: 611 D changing mode of $project_root/.tox/4/py38/bin/wheel to 755 [distlib/util.py:566]
py38: 612 D generated console scripts wheel3.8 wheel wheel3 wheel-3.8 [virtualenv/seed/embed/via_app_data/pip_install/base.py:48]
py38: 740 D copy directory $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any/pkg_resources to $project_root/.tox/4/py38/lib/python3.8/site-packages/pkg_resources [virtualenv/util/path/_sync.py:52]
py38: 759 D copy directory $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/setuptools-51.1.2-py3-none-any/_distutils_hack to $project_root/.tox/4/py38/lib/python3.8/site-packages/_distutils_hack [virtualenv/util/path/_sync.py:52]
py38: 763 D changing mode of $project_root/.tox/4/py38/bin/easy_install-3.8 to 755 [distlib/util.py:566]
py38: 764 D changing mode of $project_root/.tox/4/py38/bin/easy_install to 755 [distlib/util.py:566]
py38: 765 D changing mode of $project_root/.tox/4/py38/bin/easy_install3 to 755 [distlib/util.py:566]
py38: 765 D changing mode of $project_root/.tox/4/py38/bin/easy_install3.8 to 755 [distlib/util.py:566]
py38: 765 D generated console scripts easy_install3.8 easy_install easy_install-3.8 easy_install3 [virtualenv/seed/embed/via_app_data/pip_install/base.py:48]
py38: 985 D copy directory $libdir/virtualenv/wheel/3.8/image/1/CopyPipInstall/pip-20.3.3-py2.py3-none-any/pip-20.3.3.dist-info to $project_root/.tox/4/py38/lib/python3.8/site-packages/pip-20.3.3.dist-info [virtualenv/util/path/_sync.py:52]
py38: 994 D changing mode of $project_root/.tox/4/py38/bin/pip3.8 to 755 [distlib/util.py:566]
py38: 995 D changing mode of $project_root/.tox/4/py38/bin/pip-3.8 to 755 [distlib/util.py:566]
py38: 995 D changing mode of $project_root/.tox/4/py38/bin/pip to 755 [distlib/util.py:566]
py38: 996 D changing mode of $project_root/.tox/4/py38/bin/pip3 to 755 [distlib/util.py:566]
py38: 996 D generated console scripts pip3.8 pip3 pip-3.8 pip [virtualenv/seed/embed/via_app_data/pip_install/base.py:48]
ROOT: 996 I add activators for Bash, CShell, Fish, PowerShell, Python, Xonsh [virtualenv/run/session.py:64]
ROOT: 1002 D write $project_root/.tox/4/py38/pyvenv.cfg [virtualenv/create/pyenv_cfg.py:34]
ROOT: 1002 D 	home = $sys_prefix [virtualenv/create/pyenv_cfg.py:38]
ROOT: 1002 D 	implementation = CPython [virtualenv/create/pyenv_cfg.py:38]
ROOT: 1002 D 	version_info = 3.8.6.final.0 [virtualenv/create/pyenv_cfg.py:38]
ROOT: 1003 D 	virtualenv = 20.3.1 [virtualenv/create/pyenv_cfg.py:38]
ROOT: 1003 D 	include-system-site-packages = false [virtualenv/create/pyenv_cfg.py:38]
ROOT: 1003 D 	base-prefix = $sys_prefix [virtualenv/create/pyenv_cfg.py:38]
ROOT: 1003 D 	base-exec-prefix = $sys_prefix [virtualenv/create/pyenv_cfg.py:38]
ROOT: 1003 D 	base-executable = $path1/python3.8 [virtualenv/create/pyenv_cfg.py:38]
ROOT: 1006 E internal error [tox/session/cmd/run/single.py:53]
Traceback (most recent call last):
  File "$tox_prefix/lib/python3.9/site-packages/tox/session/cmd/run/single.py", line 41, in _evaluate
    tox_env.ensure_setup(recreate=recreate)
  File "$tox_prefix/lib/python3.9/site-packages/tox/tox_env/api.py", line 167, in ensure_setup
    self.setup()
  File "$tox_prefix/lib/python3.9/site-packages/tox/tox_env/python/runner.py", line 46, in setup
    self.install_deps()
  File "$tox_prefix/lib/python3.9/site-packages/tox/tox_env/python/runner.py", line 70, in install_deps
    requirement_file_content = requirements_file.validate_and_expand()
  File "$tox_prefix/lib/python3.9/site-packages/tox/tox_env/python/req_file.py", line 126, in validate_and_expand
    result.extend(req_file.validate_and_expand())
  File "$tox_prefix/lib/python3.9/site-packages/tox/tox_env/python/req_file.py", line 130, in validate_and_expand
    raise ValueError(line)
ValueError: --use-feature=2020-resolver
py38: FAIL ✖ in 0.78 seconds
  py38: FAIL code 2 (0.78 seconds)
  evaluation failed :( (0.82 seconds)
Exception: tox4 exited with 2
```
</details>

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/tox-dev/tox/pull/1867?src=pr&el=h1) Report
> Merging [#1867](https://codecov.io/gh/tox-dev/tox/pull/1867?src=pr&el=desc) (9e60588) into [rewrite](https://codecov.io/gh/tox-dev/tox/commit/5110d756652bf3dde5e8f91c7f5522cc2382f40d?el=desc) (5110d75) will **increase** coverage by `0.19%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/tox-dev/tox/pull/1867/graphs/tree.svg?width=650&height=150&src=pr&token=DYodAwDCZ5)](https://codecov.io/gh/tox-dev/tox/pull/1867?src=pr&el=tree)

```diff
@@             Coverage Diff              @@
##           rewrite     #1867      +/-   ##
============================================
+ Coverage    99.80%   100.00%   +0.19%     
============================================
  Files          134       133       -1     
  Lines         7358      7264      -94     
  Branches       733       709      -24     
============================================
- Hits          7344      7264      -80     
+ Misses           3         0       -3     
+ Partials        11         0      -11     
```

| Flag | Coverage Δ | |
|---|---|---|
| tests | `100.00% <100.00%> (+0.19%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/tox-dev/tox/pull/1867?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [tests/tox\_env/python/test\_req\_file.py](https://codecov.io/gh/tox-dev/tox/pull/1867/diff?src=pr&el=tree#diff-dGVzdHMvdG94X2Vudi9weXRob24vdGVzdF9yZXFfZmlsZS5weQ==) | `100.00% <ø> (ø)` | |
| [src/tox/tox\_env/python/req\_file.py](https://codecov.io/gh/tox-dev/tox/pull/1867/diff?src=pr&el=tree#diff-c3JjL3RveC90b3hfZW52L3B5dGhvbi9yZXFfZmlsZS5weQ==) | `100.00% <100.00%> (ø)` | |
| [src/tox/tox\_env/api.py](https://codecov.io/gh/tox-dev/tox/pull/1867/diff?src=pr&el=tree#diff-c3JjL3RveC90b3hfZW52L2FwaS5weQ==) | `100.00% <0.00%> (ø)` | |
| [src/tox/execute/request.py](https://codecov.io/gh/tox-dev/tox/pull/1867/diff?src=pr&el=tree#diff-c3JjL3RveC9leGVjdXRlL3JlcXVlc3QucHk=) | `100.00% <0.00%> (ø)` | |
| [...ecute/local\_sub\_process/read\_via\_thread\_windows.py](https://codecov.io/gh/tox-dev/tox/pull/1867/diff?src=pr&el=tree#diff-c3JjL3RveC9leGVjdXRlL2xvY2FsX3N1Yl9wcm9jZXNzL3JlYWRfdmlhX3RocmVhZF93aW5kb3dzLnB5) | | |
| [src/tox/tox\_env/python/api.py](https://codecov.io/gh/tox-dev/tox/pull/1867/diff?src=pr&el=tree#diff-c3JjL3RveC90b3hfZW52L3B5dGhvbi9hcGkucHk=) | `100.00% <0.00%> (+0.68%)` | :arrow_up: |
| [src/tox/config/loader/str\_convert.py](https://codecov.io/gh/tox-dev/tox/pull/1867/diff?src=pr&el=tree#diff-c3JjL3RveC9jb25maWcvbG9hZGVyL3N0cl9jb252ZXJ0LnB5) | `100.00% <0.00%> (+1.47%)` | :arrow_up: |
| [src/tox/util/spinner.py](https://codecov.io/gh/tox-dev/tox/pull/1867/diff?src=pr&el=tree#diff-c3JjL3RveC91dGlsL3NwaW5uZXIucHk=) | `100.00% <0.00%> (+2.30%)` | :arrow_up: |
| [src/tox/execute/local\_sub\_process/\_\_init\_\_.py](https://codecov.io/gh/tox-dev/tox/pull/1867/diff?src=pr&el=tree#diff-c3JjL3RveC9leGVjdXRlL2xvY2FsX3N1Yl9wcm9jZXNzL19faW5pdF9fLnB5) | `100.00% <0.00%> (+4.37%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/tox-dev/tox/pull/1867?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/tox-dev/tox/pull/1867?src=pr&el=footer). Last update [5110d75...9e60588](https://codecov.io/gh/tox-dev/tox/pull/1867?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/docs/changelog/1853.bugfix.rst b/docs/changelog/1853.bugfix.rst
new file mode 100644
index 00000000..de23d9b7
--- /dev/null
+++ b/docs/changelog/1853.bugfix.rst
@@ -0,0 +1,2 @@
+Support ``=`` separator in requirement file flags, directories as requirements and correctly set the root of the
+requirements file when using the ``--root`` CLI flag to change the root - by :user:`gaborbernat`.
diff --git a/src/tox/config/cli/env_var.py b/src/tox/config/cli/env_var.py
index 8c7098ae..e8e078f7 100644
--- a/src/tox/config/cli/env_var.py
+++ b/src/tox/config/cli/env_var.py
@@ -24,7 +24,7 @@ def get_env_var(key: str, of_type: Type[Any]) -> Optional[Tuple[Any, str]]:
             value = os.environ[environ_key]
             try:
                 source = f"env var {environ_key}"
-                result = CONVERT.to(raw=value, of_type=of_type)
+                result = CONVERT.to(raw=value, of_type=of_type, kwargs={})
                 return result, source
             except Exception as exception:  # noqa
                 logging.warning(
diff --git a/src/tox/config/cli/ini.py b/src/tox/config/cli/ini.py
index c7bdae34..b6f1cabc 100644
--- a/src/tox/config/cli/ini.py
+++ b/src/tox/config/cli/ini.py
@@ -51,7 +51,7 @@ class IniConfig:
                     result = None
                 else:
                     source = "file"
-                    value = self.ini.load(key, of_type=of_type, conf=None, env_name="tox", chain=[key])
+                    value = self.ini.load(key, of_type=of_type, conf=None, env_name="tox", chain=[key], kwargs={})
                     result = value, source
             except KeyError:  # just not found
                 result = None
diff --git a/src/tox/config/loader/api.py b/src/tox/config/loader/api.py
index 3a542653..b584a44a 100644
--- a/src/tox/config/loader/api.py
+++ b/src/tox/config/loader/api.py
@@ -72,7 +72,13 @@ class Loader(Convert[T]):
         return f"{type(self).__name__}"
 
     def load(
-        self, key: str, of_type: Type[V], conf: Optional["Config"], env_name: Optional[str], chain: List[str]
+        self,
+        key: str,
+        of_type: Type[V],
+        kwargs: Mapping[str, Any],
+        conf: Optional["Config"],
+        env_name: Optional[str],
+        chain: List[str],
     ) -> V:
         """
         Load a value.
@@ -84,11 +90,11 @@ class Loader(Convert[T]):
         :return: the converted type
         """
         if key in self.overrides:
-            return _STR_CONVERT.to(self.overrides[key].value, of_type)
+            return _STR_CONVERT.to(self.overrides[key].value, of_type, kwargs)
         raw = self.load_raw(key, conf, env_name)
         future: "Future[V]" = Future()
         with self.build(future, key, of_type, conf, env_name, raw, chain) as prepared:
-            converted = self.to(prepared, of_type)
+            converted = self.to(prepared, of_type, kwargs)
             future.set_result(converted)
         return converted
 
diff --git a/src/tox/config/loader/convert.py b/src/tox/config/loader/convert.py
index 0e8c29b8..46ea78e6 100644
--- a/src/tox/config/loader/convert.py
+++ b/src/tox/config/loader/convert.py
@@ -3,7 +3,7 @@ from abc import ABC, abstractmethod
 from collections import OrderedDict
 from enum import Enum
 from pathlib import Path
-from typing import Any, Dict, Generic, Iterator, List, Set, Tuple, Type, TypeVar, Union, cast
+from typing import Any, Dict, Generic, Iterator, List, Mapping, Set, Tuple, Type, TypeVar, Union, cast
 
 from ..types import Command, EnvList
 
@@ -21,10 +21,10 @@ V = TypeVar("V")
 class Convert(ABC, Generic[T]):
     """A class that converts a raw type to a given tox (python) type"""
 
-    def to(self, raw: T, of_type: Type[V]) -> V:
+    def to(self, raw: T, of_type: Type[V], kwargs: Mapping[str, Any]) -> V:
         from_module = getattr(of_type, "__module__", None)
         if from_module in ("typing", "typing_extensions"):
-            return self._to_typing(raw, of_type)  # type: ignore[return-value]
+            return self._to_typing(raw, of_type, kwargs)  # type: ignore[return-value]
         elif issubclass(of_type, Path):
             return self.to_path(raw)  # type: ignore[return-value]
         elif issubclass(of_type, bool):
@@ -39,21 +39,22 @@ class Convert(ABC, Generic[T]):
             return raw
         elif issubclass(of_type, Enum):
             return cast(V, getattr(of_type, str(raw)))
-        return of_type(raw)  # type: ignore[call-arg]
+        return of_type(raw, **kwargs)  # type: ignore[call-arg]
 
-    def _to_typing(self, raw: T, of_type: Type[V]) -> V:
+    def _to_typing(self, raw: T, of_type: Type[V], kwargs: Mapping[str, Any]) -> V:
         origin = getattr(of_type, "__origin__", of_type.__class__)
         result: Any = _NO_MAPPING
         if origin in (list, List):
             entry_type = of_type.__args__[0]  # type: ignore[attr-defined]
-            result = [self.to(i, entry_type) for i in self.to_list(raw, entry_type)]
+            result = [self.to(i, entry_type, kwargs) for i in self.to_list(raw, entry_type)]
         elif origin in (set, Set):
             entry_type = of_type.__args__[0]  # type: ignore[attr-defined]
-            result = {self.to(i, entry_type) for i in self.to_set(raw, entry_type)}
+            result = {self.to(i, entry_type, kwargs) for i in self.to_set(raw, entry_type)}
         elif origin in (dict, Dict):
             key_type, value_type = of_type.__args__[0], of_type.__args__[1]  # type: ignore[attr-defined]
             result = OrderedDict(
-                (self.to(k, key_type), self.to(v, value_type)) for k, v in self.to_dict(raw, (key_type, value_type))
+                (self.to(k, key_type, {}), self.to(v, value_type, {}))
+                for k, v in self.to_dict(raw, (key_type, value_type))
             )
         elif origin == Union:  # handle Optional values
             args: List[Type[Any]] = of_type.__args__  # type: ignore[attr-defined]
@@ -65,7 +66,7 @@ class Convert(ABC, Generic[T]):
                     result = None
                 else:
                     new_type = next(i for i in args if i != none)  # pragma: no cover # this will always find a element
-                    result = self.to(raw, new_type)
+                    result = self.to(raw, new_type, kwargs)
         elif origin == Literal or origin == type(Literal):
             if sys.version_info >= (3, 7):  # pragma: no cover (py37+)
                 choice = of_type.__args__
diff --git a/src/tox/config/of_type.py b/src/tox/config/of_type.py
index f82b5cc8..ba369e62 100644
--- a/src/tox/config/of_type.py
+++ b/src/tox/config/of_type.py
@@ -2,7 +2,7 @@
 Group together configuration values that belong together (such as base tox configuration, tox environment configs)
 """
 from abc import ABC, abstractmethod
-from typing import TYPE_CHECKING, Any, Callable, Generic, Iterable, List, Optional, Type, TypeVar, Union, cast
+from typing import TYPE_CHECKING, Any, Callable, Generic, Iterable, List, Mapping, Optional, Type, TypeVar, Union, cast
 
 from tox.config.loader.api import Loader
 
@@ -71,11 +71,13 @@ class ConfigDynamicDefinition(ConfigDefinition[T]):
         of_type: Type[T],
         default: Union[Callable[["Config", Optional[str]], T], T],
         post_process: Optional[Callable[[T, "Config"], T]] = None,
+        kwargs: Optional[Mapping[str, Any]] = None,
     ) -> None:
         super().__init__(keys, desc, env_name)
         self.of_type = of_type
         self.default = default
         self.post_process = post_process
+        self.kwargs: Mapping[str, Any] = {} if kwargs is None else kwargs
         self._cache: Union[object, T] = _PLACE_HOLDER
 
     def __call__(self, conf: "Config", name: Optional[str], loaders: List[Loader[T]], chain: List[str]) -> T:
@@ -84,7 +86,7 @@ class ConfigDynamicDefinition(ConfigDefinition[T]):
             for key in self.keys:
                 for loader in loaders:
                     try:
-                        value = loader.load(key, self.of_type, conf, self.env_name, chain)
+                        value = loader.load(key, self.of_type, self.kwargs, conf, self.env_name, chain)
                         found = True
                     except KeyError:
                         continue
diff --git a/src/tox/config/sets.py b/src/tox/config/sets.py
index c298cc21..08735f62 100644
--- a/src/tox/config/sets.py
+++ b/src/tox/config/sets.py
@@ -45,13 +45,13 @@ class ConfigSet:
         default: Union[Callable[["Config", Optional[str]], V], V],
         desc: str,
         post_process: Optional[Callable[[V, "Config"], V]] = None,
-        overwrite: bool = False,
+        kwargs: Optional[Mapping[str, Any]] = None,
     ) -> ConfigDynamicDefinition[V]:
         """
         Add configuration value.
         """
         keys_ = self._make_keys(keys)
-        definition = ConfigDynamicDefinition(keys_, desc, self._name, of_type, default, post_process)
+        definition = ConfigDynamicDefinition(keys_, desc, self._name, of_type, default, post_process, kwargs)
         result = self._add_conf(keys_, definition)
         return cast(ConfigDynamicDefinition[V], result)
 
diff --git a/src/tox/session/common.py b/src/tox/session/common.py
index 803aef94..3192f7ae 100644
--- a/src/tox/session/common.py
+++ b/src/tox/session/common.py
@@ -7,7 +7,7 @@ from tox.config.loader.str_convert import StrConvert
 class CliEnv:
     def __init__(self, value: Union[None, List[str], str] = None):
         if isinstance(value, str):
-            value = StrConvert().to(value, of_type=List[str])
+            value = StrConvert().to(value, of_type=List[str], kwargs={})
         self.all: bool = value is None or "ALL" in value
         self._names = value
 
diff --git a/src/tox/tox_env/python/req_file.py b/src/tox/tox_env/python/req_file.py
index b704b09c..346277d8 100644
--- a/src/tox/tox_env/python/req_file.py
+++ b/src/tox/tox_env/python/req_file.py
@@ -66,12 +66,21 @@ class RequirementsFile:
     """
 
     def __init__(self, raw: str, within_tox_ini: bool = True, root: Optional[Path] = None) -> None:
-        self._root = Path().cwd() if root is None else root
+        self._root = Path().cwd() if root is None else root.resolve()
         if within_tox_ini:  # patch the content coming from tox.ini
             lines: List[str] = []
             for line in raw.splitlines():
                 # for tox<4 supporting requirement/constraint files via -rreq.txt/-creq.txt
-                arg_match = next((o for o in ONE_ARG if line.startswith(o) and not line[len(o)].isspace()), None)
+                arg_match = next(
+                    (
+                        arg
+                        for arg in ONE_ARG
+                        if line.startswith(arg)
+                        and len(line) > len(arg)
+                        and not (line[len(arg)].isspace() or line[len(arg)] == "=")
+                    ),
+                    None,
+                )
                 if arg_match is not None:
                     line = f"{arg_match} {line[len(arg_match):]}"
                 # escape spaces
@@ -97,55 +106,60 @@ class RequirementsFile:
         result: List[str] = []
         ini_dir = self.root
         for at, line in enumerate(raw.splitlines(), start=1):
-            if line.startswith("#"):
+            line = re.sub(r"(?<!\\)\s#.*", "", line).strip()
+            if not line or line.startswith("#"):
                 continue
-            line = re.sub(r"\s#.*", "", line).strip()
-            if not line:
-                continue
-            if line.startswith("-"):  # handle flags
-                words = [i for i in re.split(r"(?<!\\)\s", line) if i]
-                first = words[0]
-                if first in NO_ARG:
-                    if len(words) != 1:
-                        raise ValueError(line)
-                    else:
-                        result.append(" ".join(words))
-                elif first in ONE_ARG:
-                    if len(words) != 2:
-                        raise ValueError(line)
-                    else:
-                        if first in ("-r", "--requirement", "-c", "--constraint"):
-                            raw_path = line[len(first) + 1 :].strip()
-                            unescaped_path = re.sub(r"\\(\s)", r"\1", raw_path)
-                            path = Path(unescaped_path)
-                            if not path.is_absolute():
-                                path = ini_dir / path
-                            if not path.exists():
-                                raise ValueError(f"requirement file path {str(path)!r} does not exist")
-                            req_file = RequirementsFile(path.read_text(), within_tox_ini=False, root=self.root)
-                            result.extend(req_file.validate_and_expand())
-                        else:
-                            result.append(" ".join(words))
-                else:
-                    raise ValueError(line)
+            if line.startswith("-"):
+                self._expand_flag(ini_dir, line, result)
             else:
-                try:
-                    req = Requirement(line)
-                    result.append(str(req))
-                except InvalidRequirement as exc:
-                    if is_url(line) or any(line.startswith(f"{v}+") and is_url(line[len(v) + 1 :]) for v in VCS):
-                        result.append(line)
-                    else:
-                        path = ini_dir / line
-                        try:
-                            is_valid_file = path.exists() and path.is_file()
-                        except OSError:  # https://bugs.python.org/issue42855 # pragma: no cover
-                            is_valid_file = False  # pragma: no cover
-                        if not is_valid_file:
-                            raise ValueError(f"{at}: {line}") from exc
-                        result.append(str(path))
+                self._expand_non_flag(at, ini_dir, line, result)
         return result
 
+    def _expand_non_flag(self, at: int, ini_dir: Path, line: str, result: List[str]) -> None:  # noqa
+        try:
+            req = Requirement(line)
+        except InvalidRequirement as exc:
+            if is_url(line) or any(line.startswith(f"{v}+") and is_url(line[len(v) + 1 :]) for v in VCS):
+                result.append(line)
+            else:
+                path = ini_dir / line
+                try:
+                    is_valid_file = path.exists() and (path.is_file() or path.is_dir())
+                except OSError:  # https://bugs.python.org/issue42855 # pragma: no cover
+                    is_valid_file = False  # pragma: no cover
+                if not is_valid_file:
+                    raise ValueError(f"{at}: {line}") from exc
+                result.append(str(path))
+        else:
+            result.append(str(req))
+
+    def _expand_flag(self, ini_dir: Path, line: str, result: List[str]) -> None:
+        words = [i for i in re.split(r"(?<!\\)(\s|=)", line, maxsplit=1)]
+        first = words[0]
+        if first in NO_ARG:
+            if len(words) != 1:  # argument provided
+                raise ValueError(line)
+            result.append(first)
+        elif first in ONE_ARG:
+            if len(words) != 3:  # no argument provided
+                raise ValueError(line)
+            if len(re.split(r"(?<!\\)\s", words[2])) > 1:  # too many arguments provided
+                raise ValueError(line)
+            if first in ("-r", "--requirement", "-c", "--constraint"):
+                raw_path = line[len(first) + 1 :].strip()
+                unescaped_path = re.sub(r"\\(\s)", r"\1", raw_path)
+                path = Path(unescaped_path)
+                if not path.is_absolute():
+                    path = ini_dir / path
+                if not path.exists():
+                    raise ValueError(f"requirement file path {str(path)!r} does not exist")
+                req_file = RequirementsFile(path.read_text(), within_tox_ini=False, root=self.root)
+                result.extend(req_file.validate_and_expand())
+            else:
+                result.append(f"{first} {words[2]}")
+        else:
+            raise ValueError(line)
+
     def _normalize_raw(self) -> str:
         # a line ending in an unescaped \ is treated as a line continuation and the newline following it is effectively
         # ignored
diff --git a/src/tox/tox_env/python/runner.py b/src/tox/tox_env/python/runner.py
index 04fe9c67..5f9703b3 100644
--- a/src/tox/tox_env/python/runner.py
+++ b/src/tox/tox_env/python/runner.py
@@ -27,10 +27,12 @@ class PythonRun(Python, RunToxEnv, ABC):
 
     def register_config(self) -> None:
         super().register_config()
+        deps_kwargs = {"root": self.core["toxinidir"]}
         self.conf.add_config(
             keys="deps",
             of_type=RequirementsFile,
-            default=RequirementsFile(""),
+            kwargs=deps_kwargs,
+            default=RequirementsFile("", **deps_kwargs),
             desc="Name of the python dependencies as specified by PEP-440",
         )
         self.core.add_config(


Test patch:
diff --git a/tests/config/loader/ini/replace/conftest.py b/tests/config/loader/ini/replace/conftest.py
index 5b28edfc..95c2f59e 100644
--- a/tests/config/loader/ini/replace/conftest.py
+++ b/tests/config/loader/ini/replace/conftest.py
@@ -27,6 +27,6 @@ def replace_one(mk_ini_conf: Callable[[str], ConfigParser], tmp_path: Path) -> R
         tox_ini = ToxIni(tox_ini_file)
         config = Config(tox_ini, overrides=[], root=tmp_path, pos_args=pos_args, work_dir=tmp_path)
         loader = config.get_env("py").loaders[0]
-        return loader.load(key="env", of_type=str, conf=config, env_name="a", chain=[])
+        return loader.load(key="env", of_type=str, conf=config, env_name="a", chain=[], kwargs={})
 
     return example  # noqa
diff --git a/tests/config/loader/ini/test_factor.py b/tests/config/loader/ini/test_factor.py
index 6dc622a2..b3ad4bc4 100644
--- a/tests/config/loader/ini/test_factor.py
+++ b/tests/config/loader/ini/test_factor.py
@@ -119,7 +119,7 @@ def test_factor_config(tox_ini_conf: ToxIniCreator) -> None:
     assert list(config) == ["py36-django15", "py36-django16", "py37-django15", "py37-django16"]
     for env in config.core["env_list"]:
         env_config = config.get_env(env)
-        env_config.add_config(keys="deps-x", of_type=List[str], default=[], desc="deps", overwrite=True)
+        env_config.add_config(keys="deps-x", of_type=List[str], default=[], desc="deps", kwargs={})
         deps = env_config["deps-x"]
         assert "pytest" in deps
         if "py36" in env:
diff --git a/tests/config/loader/ini/test_ini_loader.py b/tests/config/loader/ini/test_ini_loader.py
index f118ccd6..f2fb13d8 100644
--- a/tests/config/loader/ini/test_ini_loader.py
+++ b/tests/config/loader/ini/test_ini_loader.py
@@ -29,12 +29,12 @@ def test_ini_loader_has_no_section(mk_ini_conf: Callable[[str], ConfigParser]) -
 
 def test_ini_loader_raw(mk_ini_conf: Callable[[str], ConfigParser]) -> None:
     loader = IniLoader("tox", mk_ini_conf("[tox]\na=b"), [])
-    result = loader.load(key="a", of_type=str, conf=None, env_name=None, chain=[])
+    result = loader.load(key="a", of_type=str, conf=None, env_name=None, chain=[], kwargs={})
     assert result == "b"
 
 
 @pytest.mark.parametrize("sep", ["\n", "\r\n"])
 def test_ini_loader_raw_strip_escaped_newline(mk_ini_conf: Callable[[str], ConfigParser], sep: str) -> None:
     loader = IniLoader("tox", mk_ini_conf(f"[tox]{sep}a=b\\{sep} c"), [])
-    result = loader.load(key="a", of_type=str, conf=None, env_name=None, chain=[])
+    result = loader.load(key="a", of_type=str, conf=None, env_name=None, chain=[], kwargs={})
     assert result == "bc"
diff --git a/tests/config/loader/test_memory_loader.py b/tests/config/loader/test_memory_loader.py
index fffc699f..93bf1ec0 100644
--- a/tests/config/loader/test_memory_loader.py
+++ b/tests/config/loader/test_memory_loader.py
@@ -16,7 +16,7 @@ def test_memory_loader_repr() -> None:
 def test_memory_loader_override() -> None:
     loader = MemoryLoader(a=1)
     loader.overrides["a"] = Override("a=2")
-    loaded = loader.load("a", of_type=int, conf=None, env_name=None, chain=[])
+    loaded = loader.load("a", of_type=int, conf=None, env_name=None, chain=[], kwargs={})
     assert loaded == 2
 
 
@@ -37,8 +37,8 @@ def test_memory_loader_override() -> None:
     ],
 )
 def test_memory_loader(value: Any, of_type: Type[Any]) -> None:
-    loader = MemoryLoader(**{"a": value})
-    loaded = loader.load("a", of_type=of_type, conf=None, env_name=None, chain=[])  # noqa
+    loader = MemoryLoader(**{"a": value}, kwargs={})
+    loaded = loader.load("a", of_type=of_type, conf=None, env_name=None, chain=[], kwargs={})  # noqa
     assert loaded == value
 
 
diff --git a/tests/config/loader/test_str_convert.py b/tests/config/loader/test_str_convert.py
index 25abbde2..fba6943c 100644
--- a/tests/config/loader/test_str_convert.py
+++ b/tests/config/loader/test_str_convert.py
@@ -50,7 +50,7 @@ else:  # pragma: no cover (py38+)
     ],
 )
 def test_str_convert_ok(raw: str, value: Any, of_type: Type[Any]) -> None:
-    result = StrConvert().to(raw, of_type)  # noqa
+    result = StrConvert().to(raw, of_type, {})  # noqa
     assert result == value
 
 
@@ -64,4 +64,4 @@ def test_str_convert_ok(raw: str, value: Any, of_type: Type[Any]) -> None:
 )
 def test_str_convert_nok(raw: str, of_type: Type[Any], msg: str, exc_type: Type[Exception]) -> None:
     with pytest.raises(exc_type, match=msg):
-        result = StrConvert().to(raw, of_type)  # noqa
+        result = StrConvert().to(raw, of_type, {})  # noqa
diff --git a/tests/tox_env/python/test_req_file.py b/tests/tox_env/python/test_req_file.py
index 0e61049f..dc74c1c2 100644
--- a/tests/tox_env/python/test_req_file.py
+++ b/tests/tox_env/python/test_req_file.py
@@ -33,8 +33,10 @@ from tox.tox_env.python.req_file import ONE_ARG, RequirementsFile
         ("--find-links a", "--find-links a"),
         ("--trusted-host a", "--trusted-host a"),
         ("--use-feature a", "--use-feature a"),
+        ("--use-feature=a", "--use-feature a"),
         ("--no-binary a", "--no-binary a"),
         ("--only-binary a", "--only-binary a"),
+        ("--only-binary=a", "--only-binary a"),
         ("####### example-requirements.txt #######", ""),
         ("\t##### Requirements without Version Specifiers ######", ""),
         ("  # start", ""),
@@ -128,6 +130,7 @@ def test_requirements_txt_transitive(tmp_path: Path, flag: str) -> None:
         "--pre something",
         "--missing",
         "--index-url a b",
+        "--index-url",
         "-k",
         "magic+https://git.example.com/MyProject#egg=MyProject",
     ],