|
10 | 10 | from collections.abc import Generator |
11 | 11 | from collections.abc import Iterable |
12 | 12 | from collections.abc import Iterator |
| 13 | +from collections.abc import Mapping |
13 | 14 | from collections.abc import Sequence |
14 | 15 | import contextlib |
15 | 16 | import copy |
|
55 | 56 | from _pytest._io import TerminalWriter |
56 | 57 | from _pytest.compat import assert_never |
57 | 58 | from _pytest.config.argparsing import Argument |
| 59 | +from _pytest.config.argparsing import FILE_OR_DIR |
58 | 60 | from _pytest.config.argparsing import Parser |
59 | 61 | import _pytest.deprecated |
60 | 62 | import _pytest.hookspec |
@@ -290,23 +292,21 @@ def directory_arg(path: str, optname: str) -> str: |
290 | 292 |
|
291 | 293 |
|
292 | 294 | def get_config( |
293 | | - args: list[str] | None = None, |
| 295 | + args: Iterable[str] | None = None, |
294 | 296 | plugins: Sequence[str | _PluggyPlugin] | None = None, |
295 | 297 | ) -> Config: |
296 | 298 | # Subsequent calls to main will create a fresh instance. |
297 | 299 | pluginmanager = PytestPluginManager() |
298 | | - config = Config( |
299 | | - pluginmanager, |
300 | | - invocation_params=Config.InvocationParams( |
301 | | - args=args or (), |
302 | | - plugins=plugins, |
303 | | - dir=pathlib.Path.cwd(), |
304 | | - ), |
| 300 | + invocation_params = Config.InvocationParams( |
| 301 | + args=args or (), |
| 302 | + plugins=plugins, |
| 303 | + dir=pathlib.Path.cwd(), |
305 | 304 | ) |
| 305 | + config = Config(pluginmanager, invocation_params=invocation_params) |
306 | 306 |
|
307 | | - if args is not None: |
| 307 | + if invocation_params.args: |
308 | 308 | # Handle any "-p no:plugin" args. |
309 | | - pluginmanager.consider_preparse(args, exclude_only=True) |
| 309 | + pluginmanager.consider_preparse(invocation_params.args, exclude_only=True) |
310 | 310 |
|
311 | 311 | for spec in default_plugins: |
312 | 312 | pluginmanager.import_plugin(spec) |
@@ -1202,7 +1202,7 @@ def cwd_relative_nodeid(self, nodeid: str) -> str: |
1202 | 1202 | return nodeid |
1203 | 1203 |
|
1204 | 1204 | @classmethod |
1205 | | - def fromdictargs(cls, option_dict, args) -> Config: |
| 1205 | + def fromdictargs(cls, option_dict: Mapping[str, Any], args: list[str]) -> Config: |
1206 | 1206 | """Constructor usable for subprocesses.""" |
1207 | 1207 | config = get_config(args) |
1208 | 1208 | config.option.__dict__.update(option_dict) |
@@ -1246,35 +1246,6 @@ def pytest_load_initial_conftests(self, early_config: Config) -> None: |
1246 | 1246 | ), |
1247 | 1247 | ) |
1248 | 1248 |
|
1249 | | - def _initini(self, args: Sequence[str]) -> None: |
1250 | | - ns, unknown_args = self._parser.parse_known_and_unknown_args( |
1251 | | - args, namespace=copy.copy(self.option) |
1252 | | - ) |
1253 | | - rootpath, inipath, inicfg, ignored_config_files = determine_setup( |
1254 | | - inifile=ns.inifilename, |
1255 | | - override_ini=ns.override_ini, |
1256 | | - args=ns.file_or_dir + unknown_args, |
1257 | | - rootdir_cmd_arg=ns.rootdir or None, |
1258 | | - invocation_dir=self.invocation_params.dir, |
1259 | | - ) |
1260 | | - self._rootpath = rootpath |
1261 | | - self._inipath = inipath |
1262 | | - self._ignored_config_files = ignored_config_files |
1263 | | - self.inicfg = inicfg |
1264 | | - self._parser.extra_info["rootdir"] = str(self.rootpath) |
1265 | | - self._parser.extra_info["inifile"] = str(self.inipath) |
1266 | | - self._parser.addini("addopts", "Extra command line options", "args") |
1267 | | - self._parser.addini("minversion", "Minimally required pytest version") |
1268 | | - self._parser.addini( |
1269 | | - "pythonpath", type="paths", help="Add paths to sys.path", default=[] |
1270 | | - ) |
1271 | | - self._parser.addini( |
1272 | | - "required_plugins", |
1273 | | - "Plugins that must be present for pytest to run", |
1274 | | - type="args", |
1275 | | - default=[], |
1276 | | - ) |
1277 | | - |
1278 | 1249 | def _consider_importhook(self, args: Sequence[str]) -> None: |
1279 | 1250 | """Install the PEP 302 import hook if using assertion rewriting. |
1280 | 1251 |
|
@@ -1336,13 +1307,13 @@ def _unconfigure_python_path(self) -> None: |
1336 | 1307 |
|
1337 | 1308 | def _validate_args(self, args: list[str], via: str) -> list[str]: |
1338 | 1309 | """Validate known args.""" |
1339 | | - self._parser._config_source_hint = via # type: ignore |
| 1310 | + self._parser.extra_info["config source"] = via |
1340 | 1311 | try: |
1341 | 1312 | self._parser.parse_known_and_unknown_args( |
1342 | 1313 | args, namespace=copy.copy(self.option) |
1343 | 1314 | ) |
1344 | 1315 | finally: |
1345 | | - del self._parser._config_source_hint # type: ignore |
| 1316 | + self._parser.extra_info.pop("config source", None) |
1346 | 1317 |
|
1347 | 1318 | return args |
1348 | 1319 |
|
@@ -1399,7 +1370,35 @@ def _preparse(self, args: list[str], addopts: bool = True) -> None: |
1399 | 1370 | self._validate_args(shlex.split(env_addopts), "via PYTEST_ADDOPTS") |
1400 | 1371 | + args |
1401 | 1372 | ) |
1402 | | - self._initini(args) |
| 1373 | + |
| 1374 | + ns, unknown_args = self._parser.parse_known_and_unknown_args( |
| 1375 | + args, namespace=copy.copy(self.option) |
| 1376 | + ) |
| 1377 | + rootpath, inipath, inicfg, ignored_config_files = determine_setup( |
| 1378 | + inifile=ns.inifilename, |
| 1379 | + override_ini=ns.override_ini, |
| 1380 | + args=ns.file_or_dir + unknown_args, |
| 1381 | + rootdir_cmd_arg=ns.rootdir or None, |
| 1382 | + invocation_dir=self.invocation_params.dir, |
| 1383 | + ) |
| 1384 | + self._rootpath = rootpath |
| 1385 | + self._inipath = inipath |
| 1386 | + self._ignored_config_files = ignored_config_files |
| 1387 | + self.inicfg = inicfg |
| 1388 | + self._parser.extra_info["rootdir"] = str(self.rootpath) |
| 1389 | + self._parser.extra_info["inifile"] = str(self.inipath) |
| 1390 | + self._parser.addini("addopts", "Extra command line options", "args") |
| 1391 | + self._parser.addini("minversion", "Minimally required pytest version") |
| 1392 | + self._parser.addini( |
| 1393 | + "pythonpath", type="paths", help="Add paths to sys.path", default=[] |
| 1394 | + ) |
| 1395 | + self._parser.addini( |
| 1396 | + "required_plugins", |
| 1397 | + "Plugins that must be present for pytest to run", |
| 1398 | + type="args", |
| 1399 | + default=[], |
| 1400 | + ) |
| 1401 | + |
1403 | 1402 | if addopts: |
1404 | 1403 | args[:] = ( |
1405 | 1404 | self._validate_args(self.getini("addopts"), "via addopts config") + args |
@@ -1540,19 +1539,17 @@ def parse(self, args: list[str], addopts: bool = True) -> None: |
1540 | 1539 | self._preparse(args, addopts=addopts) |
1541 | 1540 | self._parser.after_preparse = True # type: ignore |
1542 | 1541 | try: |
1543 | | - args = self._parser.parse_setoption( |
1544 | | - args, self.option, namespace=self.option |
1545 | | - ) |
1546 | | - self.args, self.args_source = self._decide_args( |
1547 | | - args=args, |
1548 | | - pyargs=self.known_args_namespace.pyargs, |
1549 | | - testpaths=self.getini("testpaths"), |
1550 | | - invocation_dir=self.invocation_params.dir, |
1551 | | - rootpath=self.rootpath, |
1552 | | - warn=True, |
1553 | | - ) |
| 1542 | + parsed = self._parser.parse(args, namespace=self.option) |
1554 | 1543 | except PrintHelp: |
1555 | | - pass |
| 1544 | + return |
| 1545 | + self.args, self.args_source = self._decide_args( |
| 1546 | + args=getattr(parsed, FILE_OR_DIR), |
| 1547 | + pyargs=self.known_args_namespace.pyargs, |
| 1548 | + testpaths=self.getini("testpaths"), |
| 1549 | + invocation_dir=self.invocation_params.dir, |
| 1550 | + rootpath=self.rootpath, |
| 1551 | + warn=True, |
| 1552 | + ) |
1556 | 1553 |
|
1557 | 1554 | def issue_config_time_warning(self, warning: Warning, stacklevel: int) -> None: |
1558 | 1555 | """Issue and handle a warning during the "configure" stage. |
|
0 commit comments