|
5 | 5 | import argparse
|
6 | 6 | import logging
|
7 | 7 | import os
|
| 8 | +import random |
8 | 9 | import sys
|
9 |
| -from argparse import SUPPRESS, Action, ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace |
| 10 | +from argparse import SUPPRESS, Action, ArgumentDefaultsHelpFormatter, ArgumentError, ArgumentParser, Namespace |
10 | 11 | from pathlib import Path
|
11 | 12 | from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple, Type, TypeVar, cast
|
12 | 13 |
|
13 | 14 | from tox.config.loader.str_convert import StrConvert
|
14 | 15 | from tox.plugin import NAME
|
| 16 | +from tox.util.ci import is_ci |
15 | 17 |
|
16 | 18 | from .env_var import get_env_var
|
17 | 19 | from .ini import IniConfig
|
@@ -178,8 +180,75 @@ def add_command(
|
178 | 180 | excl_group = group.add_mutually_exclusive_group(**e_kwargs)
|
179 | 181 | for a_args, _, a_kwargs in arguments:
|
180 | 182 | excl_group.add_argument(*a_args, **a_kwargs)
|
| 183 | + self._add_provision_arguments(sub_parser) |
181 | 184 | return sub_parser
|
182 | 185 |
|
| 186 | + def _add_provision_arguments(self, sub_parser: ToxParser) -> None: # noqa: PLR6301 |
| 187 | + sub_parser.add_argument( |
| 188 | + "--result-json", |
| 189 | + dest="result_json", |
| 190 | + metavar="path", |
| 191 | + of_type=Path, |
| 192 | + default=None, |
| 193 | + help="write a JSON file with detailed information about all commands and results involved", |
| 194 | + ) |
| 195 | + |
| 196 | + class SeedAction(Action): |
| 197 | + def __call__( |
| 198 | + self, |
| 199 | + parser: ArgumentParser, # noqa: ARG002 |
| 200 | + namespace: Namespace, |
| 201 | + values: str | Sequence[Any] | None, |
| 202 | + option_string: str | None = None, # noqa: ARG002 |
| 203 | + ) -> None: |
| 204 | + if values == "notset": |
| 205 | + result = None |
| 206 | + else: |
| 207 | + try: |
| 208 | + result = int(cast(str, values)) |
| 209 | + if result <= 0: |
| 210 | + msg = "must be greater than zero" |
| 211 | + raise ValueError(msg) # noqa: TRY301 |
| 212 | + except ValueError as exc: |
| 213 | + raise ArgumentError(self, str(exc)) from exc |
| 214 | + setattr(namespace, self.dest, result) |
| 215 | + |
| 216 | + if os.environ.get("PYTHONHASHSEED", "random") != "random": |
| 217 | + hashseed_default = int(os.environ["PYTHONHASHSEED"]) |
| 218 | + else: |
| 219 | + hashseed_default = random.randint(1, 1024 if sys.platform == "win32" else 4294967295) # noqa: S311 |
| 220 | + sub_parser.add_argument( |
| 221 | + "--hashseed", |
| 222 | + metavar="SEED", |
| 223 | + help="set PYTHONHASHSEED to SEED before running commands. Defaults to a random integer in the range " |
| 224 | + "[1, 4294967295] ([1, 1024] on Windows). Passing 'notset' suppresses this behavior.", |
| 225 | + action=SeedAction, |
| 226 | + of_type=Optional[int], # type: ignore[arg-type] |
| 227 | + default=hashseed_default, |
| 228 | + dest="hash_seed", |
| 229 | + ) |
| 230 | + sub_parser.add_argument( |
| 231 | + "--discover", |
| 232 | + dest="discover", |
| 233 | + nargs="+", |
| 234 | + metavar="path", |
| 235 | + help="for Python discovery first try the Python executables under these paths", |
| 236 | + default=[], |
| 237 | + ) |
| 238 | + list_deps = sub_parser.add_mutually_exclusive_group() |
| 239 | + list_deps.add_argument( |
| 240 | + "--list-dependencies", |
| 241 | + action="store_true", |
| 242 | + default=is_ci(), |
| 243 | + help="list the dependencies installed during environment setup", |
| 244 | + ) |
| 245 | + list_deps.add_argument( |
| 246 | + "--no-list-dependencies", |
| 247 | + action="store_false", |
| 248 | + dest="list_dependencies", |
| 249 | + help="never list the dependencies installed during environment setup", |
| 250 | + ) |
| 251 | + |
183 | 252 | def add_argument_group(self, *args: Any, **kwargs: Any) -> Any:
|
184 | 253 | result = super().add_argument_group(*args, **kwargs)
|
185 | 254 | if self.of_cmd is None and args not in {("positional arguments",), ("optional arguments",)}:
|
|
0 commit comments