From cea105b7007039c830c92ae92aa5792e819ee487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Mon, 30 Sep 2024 20:38:15 -0700 Subject: [PATCH] True TOML config support (#3353) --- .pre-commit-config.yaml | 5 +- docs/changelog/999.feature.rst | 1 + docs/config.rst | 706 +++++++++++++----- docs/installation.rst | 47 +- docs/user_guide.rst | 412 +++++----- pyproject.toml | 21 +- src/tox/config/loader/ini/__init__.py | 6 +- src/tox/config/loader/ini/replace.py | 382 ++-------- src/tox/config/loader/replacer.py | 297 ++++++++ src/tox/config/loader/stringify.py | 4 +- src/tox/config/loader/toml/__init__.py | 109 +++ src/tox/config/loader/toml/_api.py | 17 + src/tox/config/loader/toml/_replace.py | 147 ++++ src/tox/config/loader/toml/_validate.py | 75 ++ src/tox/config/of_type.py | 16 +- src/tox/config/set_env.py | 7 +- src/tox/config/sets.py | 5 +- src/tox/config/source/api.py | 3 + src/tox/config/source/discover.py | 13 +- src/tox/config/source/ini.py | 3 - src/tox/config/source/toml_pyproject.py | 132 ++++ src/tox/config/source/toml_tox.py | 21 + .../loader/{ini/replace => }/conftest.py | 0 .../ini/replace/test_replace_env_var.py | 2 +- .../ini/replace/test_replace_os_pathsep.py | 2 +- .../loader/ini/replace/test_replace_os_sep.py | 2 +- .../ini/replace/test_replace_posargs.py | 2 +- .../ini/replace/test_replace_tox_env.py | 4 +- .../loader/ini/replace/test_replace_tty.py | 2 +- .../loader/{ini/replace => }/test_replace.py | 4 +- tests/config/loader/test_toml_loader.py | 144 ++++ tests/config/source/test_discover.py | 2 +- tests/config/source/test_toml_pyproject.py | 315 ++++++++ tests/config/source/test_toml_tox.py | 115 +++ tests/session/cmd/test_legacy.py | 4 +- tox.ini | 43 +- tox.toml | 131 ++++ 37 files changed, 2435 insertions(+), 766 deletions(-) create mode 100644 docs/changelog/999.feature.rst create mode 100644 src/tox/config/loader/replacer.py create mode 100644 src/tox/config/loader/toml/__init__.py create mode 100644 src/tox/config/loader/toml/_api.py create mode 100644 src/tox/config/loader/toml/_replace.py create mode 100644 src/tox/config/loader/toml/_validate.py create mode 100644 src/tox/config/source/toml_pyproject.py create mode 100644 src/tox/config/source/toml_tox.py rename tests/config/loader/{ini/replace => }/conftest.py (100%) rename tests/config/loader/{ini/replace => }/test_replace.py (95%) create mode 100644 tests/config/loader/test_toml_loader.py create mode 100644 tests/config/source/test_toml_pyproject.py create mode 100644 tests/config/source/test_toml_tox.py create mode 100644 tox.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1561ff14f..97e728143 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,12 +39,9 @@ repos: hooks: - id: rst-backticks - repo: https://github.com/rbubley/mirrors-prettier - rev: "v3.3.3" # Use the sha / tag you want to point at + rev: "v3.3.3" hooks: - id: prettier - additional_dependencies: - - prettier@3.3.3 - - "@prettier/plugin-xml@3.4.1" - repo: local hooks: - id: changelogs-rst diff --git a/docs/changelog/999.feature.rst b/docs/changelog/999.feature.rst new file mode 100644 index 000000000..bd4aceb3e --- /dev/null +++ b/docs/changelog/999.feature.rst @@ -0,0 +1 @@ +Native TOML configuration support - by :user:`gaborbernat`. diff --git a/docs/config.rst b/docs/config.rst index ecbbd2d92..33c3698dc 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -9,33 +9,47 @@ be set once and used for all tox environments, while environment options are app Discovery and file types ------------------------ -Out of box tox supports three configuration locations prioritized in the following order: +With regards to the configuration format, at the moment we support the following formats: -1. ``tox.ini``, -2. ``pyproject.toml``, -3. ``setup.cfg``. +- `INI `_. +- `TOML `_. -With regards to the configuration format, at the moment we only support *ini-style*. ``tox.ini`` and ``setup.cfg`` are -by nature such files, while in ``pyproject.toml`` currently you can only inline the *ini-style* config. +Out of box tox supports five configuration locations prioritized in the following order: -Note that ``setup.cfg`` requires the content to be under the ``tox:tox`` and ``testenv`` sections and is otherwise -ignored. ``pyproject.toml`` on the other hand is in TOML format. However, one can inline the *ini-style* format under -the ``tool.tox.legacy_tox_ini`` key as a multi-line string. +1. ``tox.ini`` (INI), +2. ``setup.cfg`` (INI), +3. ``pyproject.toml`` with the ``tool.tox`` table, having ``legacy_tox_ini`` key (containing INI), +4. Native ``pyproject.toml`` under the ``tool.tox`` table (TOML), +5. ``tox.toml`` (TOML). + +Historically, the INI format was created first, and TOML was added in 2024. The TOML format generally is more robust, +however is less powerful and more verbose. You should use TOML unless you need some of the more advanced features +that TOML does not support (such as conditional factors, generative environments to name a few -- however, PRs to +add support for these in TOML is welcome). + +.. _tox-ini: ``tox.ini`` ~~~~~~~~~~~ -The core settings are under the ``tox`` section while the environment sections are under the ``testenv:{env_name}`` -section. All tox environments by default inherit setting from the ``testenv`` section. This means if tox needs an option -and is not available under ``testenv:{env_name}`` will first try to use the value from ``testenv``, before falling back -to the default value for that setting. For example: + +This configuration file uses: + +- ``tox`` section to host core configuration, +- ``testenv:{env_name}`` section to host environment configuration, +- ``testenv`` section as base configuration for run environments (fallback location for missing values for a test/run + environment), +- ``pkgenv`` section as base configuration for package environments (fallback location for missing values for a package + environment). + +For example: .. code-block:: ini [tox] - min_version = 4.0 + min_version = 4.20 env_list = - py310 - py39 + 3.13 + 3.12 type [testenv] @@ -48,18 +62,22 @@ to the default value for that setting. For example: ``setup.cfg`` ~~~~~~~~~~~~~ -The core settings are under the ``tox:tox`` section while the environment sections are under the ``testenv:{env_name}`` -section. All tox environments by default inherit setting from the ``testenv`` section. This means if tox needs an option -and is not available under ``testenv:{env_name}`` will first try to use the value from ``testenv``, before falling back -to the default value for that setting. For example: +This configuration file uses: + +- ``tox:tox`` section to host core configuration, +- ``testenv:{env_name}`` section to host environment configuration, +- ``testenv`` section as base configuration for run environments (fallback location for missing values for a test/run + environment), +- ``pkgenv`` section as base configuration for package environments (fallback location for missing values for a package + environment). .. code-block:: ini [tox:tox] min_version = 4.0 env_list = - py310 - py39 + 3.13 + 3.12 type [testenv] @@ -70,12 +88,10 @@ to the default value for that setting. For example: deps = mypy commands = mypy src -``pyproject.toml`` -~~~~~~~~~~~~~~~~~~ -You can inline a ``tox.ini`` style configuration under the ``tool.tox`` section and ``legacy_tox_ini`` key. - -Below you find the specification for the *ini-style* format, but you might want to skim some -examples first and use this page as a reference. +``pyproject.toml`` - INI +~~~~~~~~~~~~~~~~~~~~~~~~ +This configuration file is equivalent to :ref:`tox.ini ` format, with the difference that the text is stored +instead inside the ``pyproject.toml`` file under the ``tool.tox`` table and ``legacy_tox_ini`` key: .. code-block:: toml @@ -97,6 +113,58 @@ examples first and use this page as a reference. commands = mypy src """ + +.. _pyproject-toml-native: + +``pyproject.toml`` - native +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We support native TOML configuration via the ``pyproject.toml`` files ``tool.tox`` table. This configuration file uses: + +- ``tool.tox`` table to host core configuration, +- ``tool.tox.env.{env_name}`` table to host environment configuration, +- ``tool.tox.env_run_base`` table as base configuration for run environments (fallback location for missing values for + a test/run environment), +- ``tool.tox.env_pkg_base`` table as base configuration for package environments (fallback location for missing values + for a package environment). + +.. code-block:: toml + + [tool.tox] + requires = ["tox>=4.19"] + env_list = ["3.13", "3.12", "type"] + + [tool.tox.env_run_base] + description = "Run test under {base_python}" + commands = [["pytest"]] + + [tool.tox.env.type] + description = "run type check on code base" + deps = ["mypy==1.11.2", "types-cachetools>=5.5.0.20240820", "types-chardet>=5.0.4.6"] + commands = [["mypy", "src{/}tox"], ["mypy", "tests"]] + +``tox.toml`` +~~~~~~~~~~~~ + +This configuration file is equivalent to :ref:`pyproject.toml - native ` with the difference +that it lives in a separate dedicated files and accordingly the ``tool.tox`` sub-table is no longer required. + +For example: + +.. code-block:: toml + + requires = ["tox>=4.19"] + env_list = ["3.13", "3.12", "type"] + + [env_run_base] + description = "Run test under {base_python}" + commands = [["pytest"]] + + [env.type] + description = "run type check on code base" + deps = ["mypy==1.11.2", "types-cachetools>=5.5.0.20240820", "types-chardet>=5.0.4.6"] + commands = [["mypy", "src{/}tox"], ["mypy", "tests"]] + .. _conf-core: Core @@ -114,13 +182,24 @@ The following options are set in the ``[tox]`` section of ``tox.ini`` or the ``[ environment that does not have this issue, and run the tox command within that environment. See :ref:`provision_tox_env` for more details. - .. code-block:: ini + .. tab:: TOML + + .. code-block:: toml + + [tool.tox.pyproject] + requires = [ + "tox>=4", + "virtualenv>20.2", + ] + + .. tab:: INI + + .. code-block:: ini [tox] requires = tox>=4 virtualenv>20.2 - .. conf:: :keys: min_version, minversion :default: @@ -208,12 +287,21 @@ The following options are set in the ``[tox]`` section of ``tox.ini`` or the ``[ A mapping of label names to environments it applies too. For example: - .. code-block:: ini + .. tab:: TOML + + .. code-block:: toml + + [tool.pyproject] + labels = { test = ["3.13", "3.12"], static = ["ruff", "mypy"] } - [tox] - labels = - test = py310, py39 - static = flake8, mypy + .. tab:: INI + + .. code-block:: ini + + [tox] + labels = + test = 3.13, 3.12 + static = ruff, mypy .. conf:: :keys: on_platform @@ -230,7 +318,7 @@ Python language core options .. versionadded:: 3.1.0 - tox allows setting the Python version for an environment via the :ref:`basepython` setting. If that's not set tox + tox allows setting the Python version for an environment via the :ref:`base_python` setting. If that's not set tox can set a default value from the environment name (e.g. ``py310`` implies Python 3.10). Matching up the Python version with the environment name has became expected at this point, leading to surprises when some configs don't do so. To help with sanity of users, an error will be raised whenever the environment name version does not match @@ -245,7 +333,7 @@ Python language core options tox environment --------------- -The following options are set in the ``[testenv]`` or ``[testenv:*]`` sections of ``tox.ini`` or ``setup.cfg``. +These are configuration for the tox environments (either packaging or run type). Base options ~~~~~~~~~~~~ @@ -494,12 +582,23 @@ Base options A list of labels to apply for this environment. For example: - .. code-block:: ini + .. tab:: TOML + + .. code-block:: toml + + [tool.pyproject.env_run_base] + labels = ["test", "core"] + [tool.pyproject.env.flake8] + labels = ["mypy"] - [testenv] - labels = test, core - [testenv:flake8] - labels = mypy + .. tab:: INI + + .. code-block:: ini + + [testenv] + labels = test, core + [testenv:flake8] + labels = mypy Execute ~~~~~~~ @@ -736,8 +835,20 @@ Python run ``-c`` (followed by a file path). For example: + .. tab:: TOML - .. code-block:: ini + .. code-block:: toml + + [tool.pyproject.env_run_base] + deps = [ + "pytest>=8", + "-r requirements.txt", + "-c constraints.txt", + ] + + .. tab:: INI + + .. code-block:: ini [testenv] deps = @@ -1019,116 +1130,243 @@ changed via ``TOX_USER_CONFIG_FILE`` environment variable. Example configuration [tox] skip_missing_interpreters = true -Substitutions -------------- -Any ``key=value`` setting in an ini-file can make use of **value substitution** -through the ``{...}`` string-substitution pattern. +Set CLI flags via environment variables +--------------------------------------- +All configuration can be overridden via environment variables too, the naming convention here is ``TOX_