Skip to content

Commit 399089a

Browse files
committed
fix: add --strict, support tox-uv's Literal, fix issue with order
1 parent d767b27 commit 399089a

File tree

2 files changed

+63
-8
lines changed

2 files changed

+63
-8
lines changed

src/tox/session/cmd/schema.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import sys
77
import typing
88
from pathlib import Path
9+
from types import NoneType
910
from typing import TYPE_CHECKING
1011

1112
import packaging.requirements
@@ -24,10 +25,11 @@
2425

2526
@impl
2627
def tox_add_option(parser: ToxParser) -> None:
27-
parser.add_command("schema", [], "Generate schema for tox configuration", gen_schema)
28+
our = parser.add_command("schema", [], "Generate schema for tox configuration", gen_schema)
29+
our.add_argument("--strict", action="store_true", help="Disallow extra properties in configuration")
2830

2931

30-
def _process_type(of_type: typing.Any) -> dict[str, typing.Any]: # noqa: PLR0911
32+
def _process_type(of_type: typing.Any) -> dict[str, typing.Any]: # noqa: C901, PLR0911
3133
if of_type in {
3234
Path,
3335
str,
@@ -36,10 +38,18 @@ def _process_type(of_type: typing.Any) -> dict[str, typing.Any]: # noqa: PLR091
3638
tox.tox_env.python.pip.req_file.PythonDeps,
3739
}:
3840
return {"type": "string"}
41+
if typing.get_origin(of_type) is typing.Union:
42+
types = [x for x in typing.get_args(of_type) if x is not NoneType]
43+
if len(types) == 1:
44+
return _process_type(types[0])
45+
msg = f"Union types are not supported: {of_type}"
46+
raise ValueError(msg)
3947
if of_type is bool:
4048
return {"type": "boolean"}
4149
if of_type is float:
4250
return {"type": "number"}
51+
if typing.get_origin(of_type) is typing.Literal:
52+
return {"enum": list(typing.get_args(of_type))}
4353
if of_type in {tox.config.types.Command, tox.config.types.EnvList}:
4454
return {"type": "array", "items": {"$ref": "#/definitions/subs"}}
4555
if typing.get_origin(of_type) in {list, set}:
@@ -82,22 +92,32 @@ def _get_schema(conf: ConfigSet, path: str) -> dict[str, dict[str, typing.Any]]:
8292

8393
def gen_schema(state: State) -> int:
8494
core = state.conf.core
95+
strict = state.conf.options.strict
8596

86-
properties = _get_schema(core, path="#/properties")
87-
97+
# Accessing this adds extra stuff to core, so we need to do it first
8898
env_properties = _get_schema(state.envs["3.13"].conf, path="#/properties/env_run_base/properties")
8999

100+
properties = _get_schema(core, path="#/properties")
101+
90102
json_schema = {
91103
"$schema": "http://json-schema.org/draft-07/schema",
92104
"$id": "https://github.com/tox-dev/tox/blob/main/src/tox/util/tox.schema.json",
93105
"type": "object",
94106
"properties": {
95107
**properties,
96-
"env_run_base": {"type": "object", "properties": env_properties},
97-
"env_pkg_base": {"$ref": "#/properties/env_run_base"},
108+
"env_run_base": {
109+
"type": "object",
110+
"properties": env_properties,
111+
"additionalProperties": not strict,
112+
},
113+
"env_pkg_base": {
114+
"$ref": "#/properties/env_run_base",
115+
"additionalProperties": not strict,
116+
},
98117
"env": {"type": "object", "patternProperties": {"^.*$": {"$ref": "#/properties/env_run_base"}}},
99118
"legacy_tox_ini": {"type": "string"},
100119
},
120+
"additionalProperties": not strict,
101121
"definitions": {
102122
"subs": {
103123
"anyOf": [

src/tox/tox.schema.json

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,38 @@
6666
},
6767
"description": "core labels"
6868
},
69+
"ignore_base_python_conflict": {
70+
"type": "boolean",
71+
"description": "do not raise error if the environment name conflicts with base python"
72+
},
73+
"ignore_basepython_conflict": {
74+
"$ref": "#/properties/ignore_base_python_conflict"
75+
},
76+
"skip_missing_interpreters": {
77+
"type": "boolean",
78+
"description": "skip running missing interpreters"
79+
},
80+
"no_package": {
81+
"type": "boolean",
82+
"description": "is there any packaging involved in this project"
83+
},
84+
"skipsdist": {
85+
"$ref": "#/properties/no_package"
86+
},
87+
"package_env": {
88+
"type": "string",
89+
"description": "tox environment used to package"
90+
},
91+
"isolated_build_env": {
92+
"$ref": "#/properties/package_env"
93+
},
94+
"package_root": {
95+
"type": "string",
96+
"description": "indicates where the packaging root file exists (historically setup.py file or pyproject.toml now)"
97+
},
98+
"setupdir": {
99+
"$ref": "#/properties/package_root"
100+
},
69101
"env_run_base": {
70102
"type": "object",
71103
"properties": {
@@ -314,10 +346,12 @@
314346
"type": "string",
315347
"description": "wheel tag to use for building applications"
316348
}
317-
}
349+
},
350+
"additionalProperties": true
318351
},
319352
"env_pkg_base": {
320-
"$ref": "#/properties/env_run_base"
353+
"$ref": "#/properties/env_run_base",
354+
"additionalProperties": true
321355
},
322356
"env": {
323357
"type": "object",
@@ -331,6 +365,7 @@
331365
"type": "string"
332366
}
333367
},
368+
"additionalProperties": true,
334369
"definitions": {
335370
"subs": {
336371
"anyOf": [

0 commit comments

Comments
 (0)