From 14a709f9261f03539be83066bfbf796aef32e18e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Mon, 23 Feb 2026 14:07:55 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20feat(tox):=20add=20tox.toml=20J?= =?UTF-8?q?SON=20Schema?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IDEs using taplo or Even Better TOML had no schema validation for standalone tox.toml files. The catalog entry points to tox's canonical schema at raw.githubusercontent.com so updates flow through without requiring PRs here. --- src/api/json/catalog.json | 6 + src/negative_test/tox/tox-invalid-type.toml | 2 + src/schema-validation.jsonc | 5 + src/schemas/json/partial-tox.json | 6 +- src/schemas/json/tox.json | 723 ++++++++++++++++++++ src/test/pyproject/tox-toml-config.toml | 9 + src/test/tox/tox-full.toml | 15 + src/test/tox/tox-minimal.toml | 2 + src/test/tox/tox-product.toml | 8 + 9 files changed, 775 insertions(+), 1 deletion(-) create mode 100644 src/negative_test/tox/tox-invalid-type.toml create mode 100644 src/schemas/json/tox.json create mode 100644 src/test/pyproject/tox-toml-config.toml create mode 100644 src/test/tox/tox-full.toml create mode 100644 src/test/tox/tox-minimal.toml create mode 100644 src/test/tox/tox-product.toml diff --git a/src/api/json/catalog.json b/src/api/json/catalog.json index ebcffee18d3..5ae6e5ef25c 100644 --- a/src/api/json/catalog.json +++ b/src/api/json/catalog.json @@ -6351,6 +6351,12 @@ "fileMatch": ["tombi.toml", "**/tombi/config.toml"], "url": "https://www.schemastore.org/tombi.json" }, + { + "name": "tox", + "description": "tox configuration for automating Python testing and task management", + "fileMatch": ["tox.toml"], + "url": "https://raw.githubusercontent.com/tox-dev/tox/main/src/tox/tox.schema.json" + }, { "name": "TextMate Grammar", "description": "Language grammar description files for TextMate and compatible editors", diff --git a/src/negative_test/tox/tox-invalid-type.toml b/src/negative_test/tox/tox-invalid-type.toml new file mode 100644 index 00000000000..ffe9558c590 --- /dev/null +++ b/src/negative_test/tox/tox-invalid-type.toml @@ -0,0 +1,2 @@ +#:schema ../../schemas/json/tox.json +env_list = 42 diff --git a/src/schema-validation.jsonc b/src/schema-validation.jsonc index 003dfae688f..76f83095ccb 100644 --- a/src/schema-validation.jsonc +++ b/src/schema-validation.jsonc @@ -328,6 +328,7 @@ "partial-poetry.json", // pyproject.json[tool.poetry] "partial-repo-review.json", // pyproject.json[tool.repo-review] "partial-tox.json", // pyproject.json[tool.tox] + "tox.json", "partial-eslint-plugins.json", // eslintrc.json[rules.*] "partial-fusion-pack-metadata.json", // minecraft-pack-mcmeta.json[fusion] "partial-fusion-texture-metadata.json", // minecraft-texture-mcmeta.json[fusion] @@ -1096,6 +1097,9 @@ "partial-pdm.json": { "externalSchema": ["partial-pdm-dockerize.json"] }, + "partial-tox.json": { + "externalSchema": ["tox.json"] + }, "partial-poetry.json": { "externalSchema": ["base.json"] }, @@ -1182,6 +1186,7 @@ "partial-setuptools-scm.json", "partial-taskipy.json", "partial-tox.json", + "tox.json", "poetry.json", "ruff.json", "tombi.json", diff --git a/src/schemas/json/partial-tox.json b/src/schemas/json/partial-tox.json index f2fb0db0d13..77526f1f046 100644 --- a/src/schemas/json/partial-tox.json +++ b/src/schemas/json/partial-tox.json @@ -4,7 +4,11 @@ "title": "Tox configuration in pyproject.toml", "description": "Schema for the [tool.tox] section in pyproject.toml", "type": "object", - "additionalProperties": true, + "allOf": [ + { + "$ref": "https://json.schemastore.org/tox.json" + } + ], "properties": { "legacy_tox_ini": { "type": "string", diff --git a/src/schemas/json/tox.json b/src/schemas/json/tox.json new file mode 100644 index 00000000000..7425371e0bb --- /dev/null +++ b/src/schemas/json/tox.json @@ -0,0 +1,723 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/tox.json", + "title": "tox configuration", + "description": "tox configuration file (tox.toml or [tool.tox] in pyproject.toml)", + "x-taplo": { + "links": { + "key": "https://tox.wiki/en/stable/config.html" + } + }, + "type": "object", + "properties": { + "tox_root": { + "type": "string", + "description": "the root directory (where the configuration file is found)" + }, + "toxinidir": { + "$ref": "#/properties/tox_root", + "description": "Deprecated: use 'tox_root' instead", + "deprecated": true + }, + "work_dir": { + "type": "string", + "description": "working directory" + }, + "toxworkdir": { + "$ref": "#/properties/work_dir", + "description": "Deprecated: use 'work_dir' instead", + "deprecated": true + }, + "temp_dir": { + "type": "string", + "description": "a folder for temporary files (is not cleaned at start)" + }, + "env_list": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/subs" + }, + { + "type": "object", + "required": [ + "product" + ], + "properties": { + "product": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "object", + "required": [ + "prefix" + ], + "properties": { + "prefix": { + "type": "string" + }, + "start": { + "type": "integer" + }, + "stop": { + "type": "integer" + } + }, + "additionalProperties": false + } + ] + }, + "description": "factor groups for cartesian product expansion" + }, + "exclude": { + "type": "array", + "items": { + "type": "string" + }, + "description": "environment names to exclude from product" + } + }, + "additionalProperties": false + } + ] + }, + "description": "define environments to automatically run" + }, + "envlist": { + "$ref": "#/properties/env_list", + "description": "Deprecated: use 'env_list' instead", + "deprecated": true + }, + "base": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "inherit missing keys from these sections" + }, + "min_version": { + "type": "string", + "description": "Define the minimal tox version required to run" + }, + "minversion": { + "$ref": "#/properties/min_version", + "description": "Deprecated: use 'min_version' instead", + "deprecated": true + }, + "provision_tox_env": { + "type": "string", + "description": "Name of the virtual environment used to provision a tox." + }, + "requires": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "Name of the virtual environment used to provision a tox." + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/subs" + }, + { + "type": "object", + "required": [ + "product" + ], + "properties": { + "product": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "object", + "required": [ + "prefix" + ], + "properties": { + "prefix": { + "type": "string" + }, + "start": { + "type": "integer" + }, + "stop": { + "type": "integer" + } + }, + "additionalProperties": false + } + ] + }, + "description": "factor groups for cartesian product expansion" + }, + "exclude": { + "type": "array", + "items": { + "type": "string" + }, + "description": "environment names to exclude from product" + } + }, + "additionalProperties": false + } + ] + } + }, + "description": "core labels" + }, + "ignore_base_python_conflict": { + "type": "boolean", + "description": "do not raise error if the environment name conflicts with base python" + }, + "ignore_basepython_conflict": { + "$ref": "#/properties/ignore_base_python_conflict", + "description": "Deprecated: use 'ignore_base_python_conflict' instead", + "deprecated": true + }, + "skip_missing_interpreters": { + "type": "boolean", + "description": "skip running missing interpreters" + }, + "no_package": { + "type": "boolean", + "description": "is there any packaging involved in this project" + }, + "skipsdist": { + "$ref": "#/properties/no_package", + "description": "Deprecated: use 'no_package' instead", + "deprecated": true + }, + "package_env": { + "type": "string", + "description": "tox environment used to package" + }, + "isolated_build_env": { + "$ref": "#/properties/package_env", + "description": "Deprecated: use 'package_env' instead", + "deprecated": true + }, + "package_root": { + "type": "string", + "description": "indicates where the packaging root file exists (historically setup.py file or pyproject.toml now)" + }, + "setupdir": { + "$ref": "#/properties/package_root", + "description": "Deprecated: use 'package_root' instead", + "deprecated": true + }, + "env_run_base": { + "type": "object", + "description": "base configuration for run environments", + "x-taplo": { + "links": { + "key": "https://tox.wiki/en/stable/config.html#run-environment" + } + }, + "properties": { + "set_env": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/subs" + }, + "description": "environment variables to set when running commands in the tox environment" + }, + "setenv": { + "$ref": "#/properties/env_run_base/properties/set_env", + "description": "Deprecated: use 'set_env' instead", + "deprecated": true + }, + "base": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "inherit missing keys from these sections" + }, + "runner": { + "type": "string", + "description": "the tox execute used to evaluate this environment" + }, + "description": { + "type": "string", + "description": "description attached to the tox environment" + }, + "depends": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/subs" + }, + { + "type": "object", + "required": [ + "product" + ], + "properties": { + "product": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "object", + "required": [ + "prefix" + ], + "properties": { + "prefix": { + "type": "string" + }, + "start": { + "type": "integer" + }, + "stop": { + "type": "integer" + } + }, + "additionalProperties": false + } + ] + }, + "description": "factor groups for cartesian product expansion" + }, + "exclude": { + "type": "array", + "items": { + "type": "string" + }, + "description": "environment names to exclude from product" + } + }, + "additionalProperties": false + } + ] + }, + "description": "tox environments that this environment depends on (must be run after those)" + }, + "labels": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "labels attached to the tox environment" + }, + "env_dir": { + "type": "string", + "description": "directory assigned to the tox environment" + }, + "envdir": { + "$ref": "#/properties/env_run_base/properties/env_dir", + "description": "Deprecated: use 'env_dir' instead", + "deprecated": true + }, + "env_tmp_dir": { + "type": "string", + "description": "a folder that is always reset at the start of the run" + }, + "envtmpdir": { + "$ref": "#/properties/env_run_base/properties/env_tmp_dir", + "description": "Deprecated: use 'env_tmp_dir' instead", + "deprecated": true + }, + "env_log_dir": { + "type": "string", + "description": "a folder for logging where tox will put logs of tool invocation" + }, + "envlogdir": { + "$ref": "#/properties/env_run_base/properties/env_log_dir", + "description": "Deprecated: use 'env_log_dir' instead", + "deprecated": true + }, + "suicide_timeout": { + "type": "number", + "description": "timeout to allow process to exit before sending SIGINT" + }, + "interrupt_timeout": { + "type": "number", + "description": "timeout before sending SIGTERM after SIGINT" + }, + "terminate_timeout": { + "type": "number", + "description": "timeout before sending SIGKILL after SIGTERM" + }, + "platform": { + "type": "string", + "description": "run on platforms that match this regular expression (empty means any platform)" + }, + "pass_env": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "environment variables to pass on to the tox environment" + }, + "passenv": { + "$ref": "#/properties/env_run_base/properties/pass_env", + "description": "Deprecated: use 'pass_env' instead", + "deprecated": true + }, + "disallow_pass_env": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "environment variable patterns to exclude after pass_env glob expansion" + }, + "parallel_show_output": { + "type": "boolean", + "description": "if set to True the content of the output will always be shown when running in parallel mode" + }, + "recreate": { + "type": "boolean", + "description": "always recreate virtual environment if this option is true, otherwise leave it up to tox" + }, + "allowlist_externals": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "external command glob to allow calling" + }, + "list_dependencies_command": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "command used to list installed packages" + }, + "pip_pre": { + "type": "boolean", + "description": "install the latest available pre-release (alpha/beta/rc) of dependencies without a specified version" + }, + "install_command": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "command used to install packages" + }, + "constraints": { + "type": "string", + "description": "constraints to apply to installed python dependencies" + }, + "constrain_package_deps": { + "type": "boolean", + "description": "If true, apply constraints during install_package_deps." + }, + "use_frozen_constraints": { + "type": "boolean", + "description": "Use the exact versions of installed deps as constraints, otherwise use the listed deps." + }, + "commands_pre": { + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + } + }, + "description": "the commands to be called before testing" + }, + "commands": { + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + } + }, + "description": "the commands to be called for testing" + }, + "commands_post": { + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + } + }, + "description": "the commands to be called after testing" + }, + "recreate_commands": { + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + } + }, + "description": "commands to run before the environment is removed during recreation (e.g. cache cleanup)" + }, + "change_dir": { + "type": "string", + "description": "change to this working directory when executing the test command" + }, + "changedir": { + "$ref": "#/properties/env_run_base/properties/change_dir", + "description": "Deprecated: use 'change_dir' instead", + "deprecated": true + }, + "args_are_paths": { + "type": "boolean", + "description": "if True rewrite relative posargs paths from cwd to change_dir" + }, + "ignore_errors": { + "type": "boolean", + "description": "when executing the commands keep going even if a sub-command exits with non-zero exit code" + }, + "commands_retry": { + "type": "integer", + "minimum": 0, + "description": "number of times to retry a failed command (0 means no retries)" + }, + "ignore_outcome": { + "type": "boolean", + "description": "if set to true a failing result of this testenv will not make tox fail (instead just warn)" + }, + "fail_fast": { + "type": "boolean", + "description": "if set to true, tox will stop executing remaining environments when this environment fails" + }, + "default_base_python": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "fallback python interpreter used when no factor or explicit base_python is defined" + }, + "base_python": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "environment identifier for python, first one found wins" + }, + "basepython": { + "$ref": "#/properties/env_run_base/properties/base_python", + "description": "Deprecated: use 'base_python' instead", + "deprecated": true + }, + "deps": { + "type": "string", + "description": "python dependencies with optional version specifiers, as specified by PEP-440" + }, + "dependency_groups": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "dependency groups to install of the target package" + }, + "extras": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + }, + "description": "extras to install of the target package" + }, + "pylock": { + "type": "string", + "description": "PEP 751 pylock.toml lock file path to install locked dependencies from" + }, + "extra_setup_commands": { + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + } + }, + "description": "commands to execute after setup (deps and package install) but before test commands" + }, + "skip_missing_interpreters": { + "type": "boolean", + "description": "override core skip_missing_interpreters for this environment" + }, + "system_site_packages": { + "type": "boolean", + "description": "create virtual environments that also have access to globally installed packages." + }, + "sitepackages": { + "$ref": "#/properties/env_run_base/properties/system_site_packages", + "description": "Deprecated: use 'system_site_packages' instead", + "deprecated": true + }, + "always_copy": { + "type": "boolean", + "description": "force virtualenv to always copy rather than symlink" + }, + "alwayscopy": { + "$ref": "#/properties/env_run_base/properties/always_copy", + "description": "Deprecated: use 'always_copy' instead", + "deprecated": true + }, + "download": { + "type": "boolean", + "description": "true if you want virtualenv to upgrade pip/wheel/setuptools to the latest version" + }, + "virtualenv_spec": { + "type": "string", + "description": "PEP 440 version spec for virtualenv (e.g. virtualenv<20.22.0). When set, tox bootstraps this version in an isolated environment and runs it via subprocess, enabling Python versions incompatible with the installed virtualenv." + }, + "skip_install": { + "type": "boolean", + "description": "skip installation" + }, + "use_develop": { + "type": "boolean", + "description": "use develop mode" + }, + "usedevelop": { + "$ref": "#/properties/env_run_base/properties/use_develop", + "description": "Deprecated: use 'use_develop' instead", + "deprecated": true + }, + "package": { + "type": "string", + "description": "package installation mode - wheel | sdist | sdist-wheel | editable | editable-legacy | deps-only | skip | external " + }, + "package_env": { + "type": "string", + "description": "tox environment used to package" + } + }, + "additionalProperties": true + }, + "env_pkg_base": { + "type": "object", + "$ref": "#/properties/env_run_base", + "description": "base configuration for packaging environments", + "x-taplo": { + "links": { + "key": "https://tox.wiki/en/stable/config.html#packaging-environment" + } + }, + "additionalProperties": true + }, + "env": { + "type": "object", + "description": "per-environment overrides (keyed by environment name)", + "x-taplo": { + "links": { + "key": "https://tox.wiki/en/stable/config.html#run-environment" + } + }, + "patternProperties": { + "^.*$": { + "$ref": "#/properties/env_run_base" + } + } + }, + "legacy_tox_ini": { + "type": "string", + "description": "tox configuration in INI format embedded in a TOML file", + "x-taplo": { + "links": { + "key": "https://tox.wiki/en/stable/config.html#pyproject-toml-ini" + } + } + } + }, + "additionalProperties": true, + "definitions": { + "subs": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "replace": { + "type": "string" + }, + "name": { + "type": "string" + }, + "default": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + } + } + ] + }, + "extend": { + "type": "boolean" + } + }, + "required": [ + "replace" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "replace": { + "type": "string" + }, + "of": { + "type": "array", + "items": { + "type": "string" + } + }, + "default": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/subs" + } + } + ] + }, + "extend": { + "type": "boolean" + } + }, + "required": [ + "replace", + "of" + ], + "additionalProperties": false + } + ] + } + } +} diff --git a/src/test/pyproject/tox-toml-config.toml b/src/test/pyproject/tox-toml-config.toml new file mode 100644 index 00000000000..9d08b9e64c3 --- /dev/null +++ b/src/test/pyproject/tox-toml-config.toml @@ -0,0 +1,9 @@ +#:schema ../../schemas/json/pyproject.json +[tool.tox] +env_list = ["py"] +no_package = true + +[tool.tox.env_run_base] +description = "run tests" +deps = "pytest" +commands = [["python", "-m", "pytest"]] diff --git a/src/test/tox/tox-full.toml b/src/test/tox/tox-full.toml new file mode 100644 index 00000000000..e4a8bf128dd --- /dev/null +++ b/src/test/tox/tox-full.toml @@ -0,0 +1,15 @@ +#:schema ../../schemas/json/tox.json +env_list = ["py", "lint"] +min_version = "4.0" +no_package = true + +[env_run_base] +description = "run tests" +deps = "pytest" +commands = [["python", "-m", "pytest"]] +pass_env = ["HOME", "CI"] +set_env = { PYTHONDONTWRITEBYTECODE = "1" } + +[env.lint] +description = "run linters" +commands = [["python", "-m", "flake8"]] diff --git a/src/test/tox/tox-minimal.toml b/src/test/tox/tox-minimal.toml new file mode 100644 index 00000000000..bd50849b3e2 --- /dev/null +++ b/src/test/tox/tox-minimal.toml @@ -0,0 +1,2 @@ +#:schema ../../schemas/json/tox.json +env_list = ["py"] diff --git a/src/test/tox/tox-product.toml b/src/test/tox/tox-product.toml new file mode 100644 index 00000000000..b1b8639e63d --- /dev/null +++ b/src/test/tox/tox-product.toml @@ -0,0 +1,8 @@ +#:schema ../../schemas/json/tox.json +env_list = [ + { product = [["py39", "py310"], ["django42", "django50"]], exclude = ["py39-django50"] } +] +no_package = true + +[env_run_base] +commands = [["python", "-m", "pytest"]] From d22d009a81e16a67f2c473ed9b7fc0990e01d72f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:43:49 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/schemas/json/tox.json | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/src/schemas/json/tox.json b/src/schemas/json/tox.json index 7425371e0bb..ceaed5ee529 100644 --- a/src/schemas/json/tox.json +++ b/src/schemas/json/tox.json @@ -41,9 +41,7 @@ }, { "type": "object", - "required": [ - "product" - ], + "required": ["product"], "properties": { "product": { "type": "array", @@ -57,9 +55,7 @@ }, { "type": "object", - "required": [ - "prefix" - ], + "required": ["prefix"], "properties": { "prefix": { "type": "string" @@ -134,9 +130,7 @@ }, { "type": "object", - "required": [ - "product" - ], + "required": ["product"], "properties": { "product": { "type": "array", @@ -150,9 +144,7 @@ }, { "type": "object", - "required": [ - "prefix" - ], + "required": ["prefix"], "properties": { "prefix": { "type": "string" @@ -270,9 +262,7 @@ }, { "type": "object", - "required": [ - "product" - ], + "required": ["product"], "properties": { "product": { "type": "array", @@ -286,9 +276,7 @@ }, { "type": "object", - "required": [ - "prefix" - ], + "required": ["prefix"], "properties": { "prefix": { "type": "string" @@ -610,8 +598,8 @@ "additionalProperties": true }, "env_pkg_base": { - "type": "object", "$ref": "#/properties/env_run_base", + "type": "object", "description": "base configuration for packaging environments", "x-taplo": { "links": { @@ -677,9 +665,7 @@ "type": "boolean" } }, - "required": [ - "replace" - ], + "required": ["replace"], "additionalProperties": false }, { @@ -711,10 +697,7 @@ "type": "boolean" } }, - "required": [ - "replace", - "of" - ], + "required": ["replace", "of"], "additionalProperties": false } ]