Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tox 3.27.1 to 4.0.9, environment var substitution failing #2732

Closed
techpriest002 opened this issue Dec 15, 2022 · 8 comments
Closed

tox 3.27.1 to 4.0.9, environment var substitution failing #2732

techpriest002 opened this issue Dec 15, 2022 · 8 comments
Labels
bug:minor does not affect many people or has no big impact help:wanted Issues that have been acknowledged, a solution determined and a PR might likely be accepted.

Comments

@techpriest002
Copy link

Issue

All of our build pipelines are failing due to what appears to be a bug with environment variable substitution in our tox.ini. The variable substitution works as expected with tox==3.27.1, but we start having issues with tox==4.0.9.

Environment

Provide at least:

  • OS: Windows
  • pip list of the host Python where tox is installed:
(.venv) C:\tmp\tox_4.0.9_bug>pip list
Package       Version
------------- -------
cachetools    5.2.0
chardet       5.1.0
colorama      0.4.6
distlib       0.3.6
filelock      3.8.2
packaging     22.0
pip           22.3.1
platformdirs  2.6.0
pluggy        1.0.0
pyproject_api 1.2.1
setuptools    65.6.3
tomli         2.0.1
tox           4.0.9
virtualenv    20.17.1
wheel         0.38.4

Output of running tox

Provide the output of tox -rvv:

(.venv) C:\tmp\tox_4.0.9_bug>tox -rvv
default: 2108 I find interpreter for spec PythonSpec(path=C:\tmp\tox_4.0.9_bug\.venv\Scripts\python.exe) [virtualenv\discovery\builtin.py:56]
default: 2134 D got python info of C:\Users\nws2293\AppData\Local\Programs\Python\Python39\python.exe from C:\Users\nws2293\AppData\Local\pypa\virtualenv\py_info\1\72aa99cb99a91779d7fa96aaf09f6d3b1207abe0138f99ab0af57c8a95fa9102.json [virtualenv\app_data\via_disk_folder.py:129]
default: 2173 I proposed PythonInfo(spec=CPython3.9.10.final.0-64, system=C:\Users\nws2293\AppData\Local\Programs\Python\Python39\python.exe, exe=C:\tmp\tox_4.0.9_bug\.venv\Scripts\python.exe, platform=win32, version='3.9.10 (tags/v3.9.10:f2f3f53, Jan 17 2022, 15:14:21) [MSC v.1929 64 bit (AMD64)]', encoding_fs_io=utf-8-cp1252) [virtualenv\discovery\builtin.py:63]
default: 2174 D accepted PythonInfo(spec=CPython3.9.10.final.0-64, system=C:\Users\nws2293\AppData\Local\Programs\Python\Python39\python.exe, exe=C:\tmp\tox_4.0.9_bug\.venv\Scripts\python.exe, platform=win32, version='3.9.10 (tags/v3.9.10:f2f3f53, Jan 17 2022, 15:14:21) [MSC v.1929 64 bit (AMD64)]', encoding_fs_io=utf-8-cp1252) [virtualenv\discovery\builtin.py:65]
default: 2203 D symlink on filesystem does not work [virtualenv\info.py:43]
default: 2207 D filesystem is not case-sensitive [virtualenv\info.py:24]
default: 2420 I create virtual environment via CPython3Windows(dest=C:\tmp\tox_4.0.9_bug\.tox\default, clear=False, no_vcs_ignore=False, global=False) [virtualenv\run\session.py:48]
default: 2422 D create folder C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages [virtualenv\util\path\_sync.py:9]
default: 2427 D create folder C:\tmp\tox_4.0.9_bug\.tox\default\Scripts [virtualenv\util\path\_sync.py:9]
default: 2429 D write C:\tmp\tox_4.0.9_bug\.tox\default\pyvenv.cfg [virtualenv\create\pyenv_cfg.py:30]
default: 2430 D         home = C:\Users\nws2293\AppData\Local\Programs\Python\Python39 [virtualenv\create\pyenv_cfg.py:34]
default: 2431 D         implementation = CPython [virtualenv\create\pyenv_cfg.py:34]
default: 2431 D         version_info = 3.9.10.final.0 [virtualenv\create\pyenv_cfg.py:34]
default: 2432 D         virtualenv = 20.17.1 [virtualenv\create\pyenv_cfg.py:34]
default: 2433 D         include-system-site-packages = false [virtualenv\create\pyenv_cfg.py:34]
default: 2434 D         base-prefix = C:\Users\nws2293\AppData\Local\Programs\Python\Python39 [virtualenv\create\pyenv_cfg.py:34]
default: 2434 D         base-exec-prefix = C:\Users\nws2293\AppData\Local\Programs\Python\Python39 [virtualenv\create\pyenv_cfg.py:34]
default: 2434 D         base-executable = C:\Users\nws2293\AppData\Local\Programs\Python\Python39\python.exe [virtualenv\create\pyenv_cfg.py:34]
default: 2439 D copy C:\Users\nws2293\AppData\Local\Programs\Python\Python39\Lib\venv\scripts\nt\python.exe to C:\tmp\tox_4.0.9_bug\.tox\default\Scripts\python.exe [virtualenv\util\path\_sync.py:36]        
default: 2448 D copy C:\Users\nws2293\AppData\Local\Programs\Python\Python39\Lib\venv\scripts\nt\pythonw.exe to C:\tmp\tox_4.0.9_bug\.tox\default\Scripts\pythonw.exe [virtualenv\util\path\_sync.py:36]
default: 2466 D create virtualenv import hook file C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\_virtualenv.pth [virtualenv\create\via_global_ref\api.py:89]
default: 2473 D create C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\_virtualenv.py [virtualenv\create\via_global_ref\api.py:92]
default: 2480 D ============================== target debug ============================== [virtualenv\run\session.py:50]
default: 2481 D debug via 'C:\tmp\tox_4.0.9_bug\.tox\default\Scripts\python.exe' 'C:\tmp\tox_4.0.9_bug\.venv\lib\site-packages\virtualenv\create\debug.py' [virtualenv\create\creator.py:197]
default: 2480 D {
  "sys": {
    "executable": "C:\\tmp\\tox_4.0.9_bug\\.tox\\default\\Scripts\\python.exe",
    "_base_executable": "C:\\Users\\nws2293\\AppData\\Local\\Programs\\Python\\Python39\\python.exe",
    "prefix": "C:\\tmp\\tox_4.0.9_bug\\.tox\\default",
    "base_prefix": "C:\\Users\\nws2293\\AppData\\Local\\Programs\\Python\\Python39",
    "real_prefix": null,
    "exec_prefix": "C:\\tmp\\tox_4.0.9_bug\\.tox\\default",
    "base_exec_prefix": "C:\\Users\\nws2293\\AppData\\Local\\Programs\\Python\\Python39",
    "path": [
      "C:\\Users\\nws2293\\AppData\\Local\\Programs\\Python\\Python39\\python39.zip",
      "C:\\Users\\nws2293\\AppData\\Local\\Programs\\Python\\Python39\\DLLs",
      "C:\\Users\\nws2293\\AppData\\Local\\Programs\\Python\\Python39\\lib",
      "C:\\Users\\nws2293\\AppData\\Local\\Programs\\Python\\Python39",
      "C:\\tmp\\tox_4.0.9_bug\\.tox\\default",
      "C:\\tmp\\tox_4.0.9_bug\\.tox\\default\\lib\\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": "cp1252"
  },
  "version": "3.9.10 (tags/v3.9.10:f2f3f53, Jan 17 2022, 15:14:21) [MSC v.1929 64 bit (AMD64)]",
  "makefile_filename": "C:\\Users\\nws2293\\AppData\\Local\\Programs\\Python\\Python39\\Lib\\config\\Makefile",
  "os": "<module 'os' from 'C:\\\\Users\\\\nws2293\\\\AppData\\\\Local\\\\Programs\\\\Python\\\\Python39\\\\lib\\\\os.py'>",
  "site": "<module 'site' from 'C:\\\\Users\\\\nws2293\\\\AppData\\\\Local\\\\Programs\\\\Python\\\\Python39\\\\lib\\\\site.py'>",
  "datetime": "<module 'datetime' from 'C:\\\\Users\\\\nws2293\\\\AppData\\\\Local\\\\Programs\\\\Python\\\\Python39\\\\lib\\\\datetime.py'>",
  "math": "<module 'math' (built-in)>",
  "json": "<module 'json' from 'C:\\\\Users\\\\nws2293\\\\AppData\\\\Local\\\\Programs\\\\Python\\\\Python39\\\\lib\\\\json\\\\__init__.py'>"
} [virtualenv\run\session.py:51]
default: 3034 I add seed packages via FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=C:\Users\nws2293\AppData\Local\pypa\virtualenv) [virtualenv\run\session.py:55]
default: 3051 D got embed update of distribution setuptools from C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\embed\3\setuptools.json [virtualenv\app_data\via_disk_folder.py:129]
default: 3052 D got embed update of distribution pip from C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\embed\3\pip.json [virtualenv\app_data\via_disk_folder.py:129]
default: 3053 D got embed update of distribution wheel from C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\embed\3\wheel.json [virtualenv\app_data\via_disk_folder.py:129]
default: 3060 D install setuptools from wheel C:\tmp\tox_4.0.9_bug\.venv\lib\site-packages\virtualenv\seed\wheels\embed\setuptools-65.6.3-py3-none-any.whl via CopyPipInstall [virtualenv\seed\embed\via_app_data\via_app_data.py:47]
default: 3062 D install pip from wheel C:\tmp\tox_4.0.9_bug\.venv\lib\site-packages\virtualenv\seed\wheels\embed\pip-22.3.1-py3-none-any.whl via CopyPipInstall [virtualenv\seed\embed\via_app_data\via_app_data.py:47]
default: 3063 D install wheel from wheel C:\tmp\tox_4.0.9_bug\.venv\lib\site-packages\virtualenv\seed\wheels\embed\wheel-0.38.4-py3-none-any.whl via CopyPipInstall [virtualenv\seed\embed\via_app_data\via_app_data.py:47]
default: 3077 D copy directory C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\pip-22.3.1-py3-none-any\pip to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\pip [virtualenv\util\path\_sync.py:36]
default: 3078 D copy C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\setuptools-65.6.3-py3-none-any\distutils-precedence.pth to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\distutils-precedence.pth [virtualenv\util\path\_sync.py:36]
default: 3080 D copy directory C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\wheel-0.38.4-py3-none-any\wheel to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\wheel [virtualenv\util\path\_sync.py:36]
default: 3094 D copy directory C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\setuptools-65.6.3-py3-none-any\pkg_resources to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\pkg_resources [virtualenv\util\path\_sync.py:36]
default: 3399 D copy directory C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\wheel-0.38.4-py3-none-any\wheel-0.38.4.dist-info to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\wheel-0.38.4.dist-info [virtualenv\util\path\_sync.py:36]
default: 3515 D copy C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\wheel-0.38.4-py3-none-any\wheel-0.38.4.virtualenv to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\wheel-0.38.4.virtualenv [virtualenv\util\path\_sync.py:36]
default: 3583 D generated console scripts wheel3.9.exe wheel-3.9.exe wheel3.exe wheel.exe [virtualenv\seed\embed\via_app_data\pip_install\base.py:41]
default: 3911 D copy directory C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\setuptools-65.6.3-py3-none-any\setuptools to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\setuptools [virtualenv\util\path\_sync.py:36]
default: 6578 D copy directory C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\setuptools-65.6.3-py3-none-any\setuptools-65.6.3.dist-info to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\setuptools-65.6.3.dist-info [virtualenv\util\path\_sync.py:36]
default: 6686 D copy C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\setuptools-65.6.3-py3-none-any\setuptools-65.6.3.virtualenv to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\setuptools-65.6.3.virtualenv [virtualenv\util\path\_sync.py:36]
default: 6693 D copy directory C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\setuptools-65.6.3-py3-none-any\_distutils_hack to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\_distutils_hack [virtualenv\util\path\_sync.py:36]
default: 6737 D generated console scripts  [virtualenv\seed\embed\via_app_data\pip_install\base.py:41]
default: 10295 D copy directory C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\pip-22.3.1-py3-none-any\pip-22.3.1.dist-info to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\pip-22.3.1.dist-info [virtualenv\util\path\_sync.py:36]
default: 10382 D copy C:\Users\nws2293\AppData\Local\pypa\virtualenv\wheel\3.9\image\1\CopyPipInstall\pip-22.3.1-py3-none-any\pip-22.3.1.virtualenv to C:\tmp\tox_4.0.9_bug\.tox\default\Lib\site-packages\pip-22.3.1.virtualenv [virtualenv\util\path\_sync.py:36]
default: 10413 D generated console scripts pip.exe pip3.9.exe pip-3.9.exe pip3.exe [virtualenv\seed\embed\via_app_data\pip_install\base.py:41]
default: 10413 I add activators for Bash, Batch, Fish, Nushell, PowerShell, Python [virtualenv\run\session.py:61]
default: 10513 D write C:\tmp\tox_4.0.9_bug\.tox\default\pyvenv.cfg [virtualenv\create\pyenv_cfg.py:30]
default: 10513 D        home = C:\Users\nws2293\AppData\Local\Programs\Python\Python39 [virtualenv\create\pyenv_cfg.py:34]
default: 10514 D        implementation = CPython [virtualenv\create\pyenv_cfg.py:34]
default: 10514 D        version_info = 3.9.10.final.0 [virtualenv\create\pyenv_cfg.py:34]
default: 10514 D        virtualenv = 20.17.1 [virtualenv\create\pyenv_cfg.py:34]
default: 10515 D        include-system-site-packages = false [virtualenv\create\pyenv_cfg.py:34]
default: 10515 D        base-prefix = C:\Users\nws2293\AppData\Local\Programs\Python\Python39 [virtualenv\create\pyenv_cfg.py:34]
default: 10516 D        base-exec-prefix = C:\Users\nws2293\AppData\Local\Programs\Python\Python39 [virtualenv\create\pyenv_cfg.py:34]
default: 10516 D        base-executable = C:\Users\nws2293\AppData\Local\Programs\Python\Python39\python.exe [virtualenv\create\pyenv_cfg.py:34]
default: 10534 W commands[0]> pytest [tox\tox_env\api.py:417]
default: 10713 E failed with pytest is not allowed, use allowlist_externals to allow it [tox\session\cmd\run\single.py:54]
  default: FAIL code 1 (8.64 seconds)
  evaluation failed :( (9.83 seconds)

Minimal example

This is a stripped down tox.ini file, "C:\tmp\tox_4.0.9_bug\tox.ini".

[tox]
minversion = 3.24
envlist = default
isolated_build = True


[testenv]
description = Invoke pytest to run automated tests
passenv =
    HOME
    SETUPTOOLS_*
setenv =
    TOXINIDIR = {toxinidir}


[testenv:{docs}]
description =
    docs: Pretend to invoke sphinx-build to build the docs
skip_install = True
passenv =
    SETUPTOOLS_*
setenv =
    DOCSDIR = {toxinidir}{/}docs
    BUILDDIR = {toxinidir}{/}docs{/}_build
    docs: BUILD = html
commands =
    ; sphinx-build --color -b {env:BUILD} -d "{env:BUILDDIR}{/}doctrees" "{env:DOCSDIR}" "{env:BUILDDIR}{/}{env:BUILD}" {posargs}
    python -c 'print("{env:BUILD} -- {env:BUILDDIR}{/}{env:BUILD}")'

If I run "tox -e docs" with tox 4.0.9, this is the output. Notice that the substitution of {env:BUILD} works in the first part of the line but not in the second part following the {/}:

(.venv) C:\tmp\tox_4.0.9_bug>tox -e docs
docs: commands[0]> python -c "print(\"html -- C:\tmp\tox_4.0.9_bug\docs\_build{env:BUILD}\")"
html -- C:      mp      ox_4.0.9_bug\docs\_build{env:BUILD}
  docs: OK (5.73=setup[5.16]+cmd[0.58] seconds)
  congratulations :) (6.73 seconds)

If I run "tox -e docs" with tox 3.27.1, this is the output:

C:\tmp\tox_4.0.9_bug>tox -e docs
docs run-test-pre: PYTHONHASHSEED='297'
docs run-test: commands[0] | python -c 'print("html -- C:\tmp\tox_4.0.9_bug\docs\_build\html")'
html -- C:      mp      ox_4.0.9_bug\docs\_build\html
  docs: commands succeeded
  congratulations :)
@gaborbernat
Copy link
Member

❯ tox -e docs
docs: commands[0]> python -c 'print("html -- /Users/bgabor8/git/github/tox/magic/docs/_build/html")'
html -- /Users/bgabor8/git/github/tox/magic/docs/_build/html
  docs: OK (0.20=setup[0.18]+cmd[0.02] seconds)
  congratulations :) (0.22 seconds)

I'm failing to replicate this. Can you provide a complete repository that manifests this? Please also try with tox 4.0.11.

@gaborbernat gaborbernat added the needs:reproducer ideally a failing test marked as xfail. If that is not possible exact instructions to reproduce label Dec 15, 2022
@techpriest002
Copy link
Author

I created a minimal repo here: https://github.com/techpriest002/tox_substitution_issue.git

I also tried with tox 4.0.11, but I am seeing the same behavior. Below are the commands I used to clone the repo above and prepare the environment:

C:\WINDOWS\system32>cd \Users\nab1234\source\repos

C:\Users\nab1234\source\repos>git clone https://github.com/techpriest002/tox_substitution_issue.git

C:\Users\nab1234\source\repos\tox_substitution_issue>"C:\Users\nab1234\AppData\Local\Programs\Python\Python39\python.exe" -m venv .venv

C:\Users\nab1234\source\repos\tox_substitution_issue>.venv\Scripts\activate

(.venv) C:\Users\nab1234\source\repos\tox_substitution_issue>pip install -r requirements.txt

(.venv) C:\Users\nab1234\source\repos\tox_substitution_issue>tox -e docs
docs: commands[0]> python -c "print(r\"html -- C:\Users\nab1234\source\repos\tox_substitution_issue\docs\_build{env:BUILD}\")"
html -- C:\Users\nab1234\source\repos\tox_substitution_issue\docs\_build{env:BUILD}
  docs: OK (4.67=setup[4.17]+cmd[0.50] seconds)
  congratulations :) (5.27 seconds)

(.venv) C:\Users\nab1234\source\repos\tox_substitution_issue>tox --version
4.0.11 from C:\Users\nab1234\source\repos\tox_substitution_issue\.venv\lib\site-packages\tox\__init__.py

For whatever reason, the {/}{env:BUILD} piece seems to be the issue. If I replace {/} with a standard /, the substitution works.

@gaborbernat gaborbernat added bug:minor does not affect many people or has no big impact help:wanted Issues that have been acknowledged, a solution determined and a PR might likely be accepted. and removed needs:reproducer ideally a failing test marked as xfail. If that is not possible exact instructions to reproduce labels Dec 16, 2022
@gaborbernat gaborbernat added this to the 4.0.x milestone Dec 16, 2022
@masenf
Copy link
Collaborator

masenf commented Dec 17, 2022

It looks like there are two issues here:

  1. backslash of special characters is always eager: \\{env:BUILD} reproduces a similar issue on Unix systems, where I would expect the two backslashes to escape to a literal backslash and not affect the proceeding left curly brace.

  2. On Windows, once that {/} expands to backslash it then escapes the following character, instead it should just be a literal os.sep in the resulting value, with no further substitution or effect.

I have an idea for a fix.

masenf added a commit to masenf/tox that referenced this issue Dec 17, 2022
explicit test case for issue tox-dev#2732 which affects
{/} os.sep replacement on windows platform.
masenf added a commit to masenf/tox that referenced this issue Dec 17, 2022
1. Split the value to be replaced on double
backslash.
2. If there is more than 1 split, recursively
perform replace on each sub value.
3. Rejoin replaced sub values on single backslash.

This allows "\\" to be an escape for "\" while
preserving recursive expansion semantics, and
not having already-escaped backslashes affect
processing replacements in other parts of
the string.

Fixes tox-dev#2732
masenf added a commit to masenf/tox that referenced this issue Dec 17, 2022
if the replaced value is a single backslash, then process replace on the
left and right parts of the value separately so that the replacement
cannot act as an escape in other parts of the value.

Fixes tox-dev#2732
masenf added a commit to masenf/tox that referenced this issue Dec 17, 2022
@masenf masenf mentioned this issue Dec 17, 2022
5 tasks
@masenf
Copy link
Collaborator

masenf commented Dec 20, 2022

The simple solution that I had proposed over the weekend does not work when the double backslash escape appears nested inside another expression, like {env:_:this\\does not work}.

The simple solution was splitting the string on double backslash and doing the replace on the inbetween sections of string, but this ultimately breaks the expression since it would lose its trailing }.

A proper solution is needed which recursively replaces sub-parts of the expression, while respecting the backslash escape.

I plan to work on this, but am currently focused on a different project.

masenf added a commit to masenf/tox that referenced this issue Dec 31, 2022
explicit test case for issue tox-dev#2732 which affects
{/} os.sep replacement on windows platform.
masenf added a commit to masenf/tox that referenced this issue Dec 31, 2022
explicit test case for issue tox-dev#2732 which affects
{/} os.sep replacement on windows platform.

test_replace_os_sep_subexp_regression

WiP
@masenf
Copy link
Collaborator

masenf commented Dec 31, 2022

I finally got around to rewriting the replace parser, so progress is being made on resolving this issue, and cleaning up other edge cases.

Some related context in issue #1708, which tells me replace expression semantics may have been unclear for a while. By that, I'm hesitant to push for such a rewrite without clearly documenting the new behavior and ensuring good regression testing. I already have at least 5 test cases which pass using the new parser and fail using the old parser. I think the "new" way is more correct, but since this is a behavior change, users may be affected by it.

The biggest change is that parsing is now iterative through the string: it will never recursively combine and replace anything that originated from a replacement.

So if ENV={env:ENV} and the config includes {env:ENV}, the new parser won't trigger infinite replacing because after the expression is replaced, it's added to the "output" and not considered again for future replacements. This seems safer to me, because you can't get the edge case that an adjacent replacement then affects it's neighbor, such as a variable ending in \, causing the following {posargs} to have it's \{ escaped.

For example, it's enough in current tox 4 to get into an infinite loop via

[testenv]
setenv =
    FOO=\{env:BAR}
    BAR=\{env:FOO}
commands =
    python -c print("{env:FOO}")

With my new parser, this just prints {env:BAR}.

I think this is the less astonishing approach, because you can imagine silliness like:

[testenv]
setenv =
    FOO={env
    BAR=:WHAT:WT
    BAZ=F}
commands =
    python -c 'print("{env:FOO}{env:BAR}{env:BAZ}")'

With the new parser, that prints {env:WHAT:WTF}.

With the current parser, we see WTF, meaning that it combines the replaced values and reprocesses the result with no reliable way to opt out.

Using the new parser design, we can selectively allow recursive replacement via a different syntax, such as ${ ... }. Allow the single { for regular, simple replacement, and ${ to opt-in to something resembling the current behavior (but with more control over where the recursion is bound).

@masenf
Copy link
Collaborator

masenf commented Jan 2, 2023

@gaborbernat in the v4 docs, I'm not finding the config substitutions section that describes the behavior relevant to this issue. Did that end up somewhere else in the docs?

If not, I can migrate the relevant v3 content, remove the explicit examples (which are already enumerated on the v4 config page), and describe the new semantics as part of this upcoming PR.

@gaborbernat
Copy link
Member

Go ahead with that 👍 we didn't migrate. Just make sure to explain this in a Ini configuration parser section and not generic configuration section.

masenf added a commit to masenf/tox that referenced this issue Jan 15, 2023
explicit test case for issue tox-dev#2732 which affects
{/} os.sep replacement on windows platform.

test_replace_os_sep_subexp_regression

WiP
@masenf masenf mentioned this issue Jan 25, 2023
5 tasks
@masenf
Copy link
Collaborator

masenf commented Jan 25, 2023

There were some additional issues with the reproducer posted here that are addressed in tox-4.4.0, specially around how backslash in paths are handled on windows.

PS C:\Users\masen\code\repro-2732> tox -e docs
docs: recreate env because constraint options changed: old=None new={'constrain_package_deps': True, 'use_frozen_constraints': False}
docs: remove tox env folder C:\Users\masen\code\repro-2732\.tox\docs
docs: commands[0]> python -c "print(\"html -- C:\\Users\\masen\\code\\repro-2732\\docs\\_build\\html\")"
html -- C:\Users\masen\code\repro-2732\docs\_build\html
  docs: OK (0.58=setup[0.42]+cmd[0.16] seconds)
  congratulations :) (0.67 seconds)
PS C:\Users\masen\code\repro-2732> tox --version
4.4.0 from C:\Users\masen\AppData\Local\Programs\Python\Python311\Lib\site-packages\tox\__init__.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug:minor does not affect many people or has no big impact help:wanted Issues that have been acknowledged, a solution determined and a PR might likely be accepted.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants