Merge pull request #8695 from bluetech/export-parser
argparsing: export Parser and OptionGroup for typing purposes
This commit is contained in:
		
						commit
						1b5f5326d7
					
				|  | @ -1,7 +1,7 @@ | ||||||
| Added :meth:`cache.mkdir() <pytest.Cache.mkdir>`, which is similar to the existing :meth:`cache.makedir() <pytest.Cache.makedir>`, | Added :meth:`cache.mkdir() <pytest.Cache.mkdir>`, which is similar to the existing :meth:`cache.makedir() <pytest.Cache.makedir>`, | ||||||
| but returns a :class:`pathlib.Path` instead of a legacy ``py.path.local``. | but returns a :class:`pathlib.Path` instead of a legacy ``py.path.local``. | ||||||
| 
 | 
 | ||||||
| Added a ``paths`` type to :meth:`parser.addini() <_pytest.config.argparsing.Parser.addini>`, | Added a ``paths`` type to :meth:`parser.addini() <pytest.Parser.addini>`, | ||||||
| as in ``parser.addini("mypaths", "my paths", type="paths")``, | as in ``parser.addini("mypaths", "my paths", type="paths")``, | ||||||
| which is similar to the existing ``pathlist``, | which is similar to the existing ``pathlist``, | ||||||
| but returns a list of :class:`pathlib.Path` instead of legacy ``py.path.local``. | but returns a list of :class:`pathlib.Path` instead of legacy ``py.path.local``. | ||||||
|  |  | ||||||
|  | @ -6,5 +6,7 @@ Directly constructing the following classes is now deprecated: | ||||||
| - ``_pytest.python.Metafunc`` | - ``_pytest.python.Metafunc`` | ||||||
| - ``_pytest.runner.CallInfo`` | - ``_pytest.runner.CallInfo`` | ||||||
| - ``_pytest._code.ExceptionInfo`` | - ``_pytest._code.ExceptionInfo`` | ||||||
|  | - ``_pytest.config.argparsing.Parser`` | ||||||
|  | - ``_pytest.config.argparsing.OptionGroup`` | ||||||
| 
 | 
 | ||||||
| These have always been considered private, but now issue a deprecation warning, which may become a hard error in pytest 7.0.0. | These have always been considered private, but now issue a deprecation warning, which may become a hard error in pytest 7.0.0. | ||||||
|  |  | ||||||
|  | @ -8,6 +8,8 @@ The newly-exported types are: | ||||||
| - ``pytest.Metafunc`` for the :class:`metafunc <pytest.MarkGenerator>` argument to the :func:`pytest_generate_tests <pytest.hookspec.pytest_generate_tests>` hook. | - ``pytest.Metafunc`` for the :class:`metafunc <pytest.MarkGenerator>` argument to the :func:`pytest_generate_tests <pytest.hookspec.pytest_generate_tests>` hook. | ||||||
| - ``pytest.CallInfo`` for the :class:`CallInfo <pytest.CallInfo>` type passed to various hooks. | - ``pytest.CallInfo`` for the :class:`CallInfo <pytest.CallInfo>` type passed to various hooks. | ||||||
| - ``pytest.ExceptionInfo`` for the :class:`ExceptionInfo <pytest.ExceptionInfo>` type returned from :func:`pytest.raises` and passed to various hooks. | - ``pytest.ExceptionInfo`` for the :class:`ExceptionInfo <pytest.ExceptionInfo>` type returned from :func:`pytest.raises` and passed to various hooks. | ||||||
|  | - ``pytest.Parser`` for the :class:`Parser <pytest.Parser>` type passed to the :func:`pytest_addoption <pytest.hookspec.pytest_addoption>` hook. | ||||||
|  | - ``pytest.OptionGroup`` for the :class:`OptionGroup <pytest.OptionGroup>` type returned from the :func:`parser.addgroup <pytest.Parser.getgroup>` method. | ||||||
| 
 | 
 | ||||||
| Constructing them directly is not supported; they are only meant for use in type annotations. | Constructing them directly is not supported; they are only meant for use in type annotations. | ||||||
| Doing so will emit a deprecation warning, and may become a hard-error in pytest 7.0. | Doing so will emit a deprecation warning, and may become a hard-error in pytest 7.0. | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| Several behaviors of :meth:`Parser.addoption <_pytest.config.argparsing.Parser.addoption>` are now | Several behaviors of :meth:`Parser.addoption <pytest.Parser.addoption>` are now | ||||||
| scheduled for removal in pytest 7 (deprecated since pytest 2.4.0): | scheduled for removal in pytest 7 (deprecated since pytest 2.4.0): | ||||||
| 
 | 
 | ||||||
| - ``parser.addoption(..., help=".. %default ..")`` - use ``%(default)s`` instead. | - ``parser.addoption(..., help=".. %default ..")`` - use ``%(default)s`` instead. | ||||||
|  |  | ||||||
|  | @ -48,7 +48,7 @@ Backward compatibilities in ``Parser.addoption`` | ||||||
| 
 | 
 | ||||||
| .. deprecated:: 2.4 | .. deprecated:: 2.4 | ||||||
| 
 | 
 | ||||||
| Several behaviors of :meth:`Parser.addoption <_pytest.config.argparsing.Parser.addoption>` are now | Several behaviors of :meth:`Parser.addoption <pytest.Parser.addoption>` are now | ||||||
| scheduled for removal in pytest 7 (deprecated since pytest 2.4.0): | scheduled for removal in pytest 7 (deprecated since pytest 2.4.0): | ||||||
| 
 | 
 | ||||||
| - ``parser.addoption(..., help=".. %default ..")`` - use ``%(default)s`` instead. | - ``parser.addoption(..., help=".. %default ..")`` - use ``%(default)s`` instead. | ||||||
|  |  | ||||||
|  | @ -889,9 +889,14 @@ Node | ||||||
| Parser | Parser | ||||||
| ~~~~~~ | ~~~~~~ | ||||||
| 
 | 
 | ||||||
| .. autoclass:: _pytest.config.argparsing.Parser() | .. autoclass:: pytest.Parser() | ||||||
|     :members: |     :members: | ||||||
| 
 | 
 | ||||||
|  | OptionGroup | ||||||
|  | ~~~~~~~~~~~ | ||||||
|  | 
 | ||||||
|  | .. autoclass:: pytest.OptionGroup() | ||||||
|  |     :members: | ||||||
| 
 | 
 | ||||||
| PytestPluginManager | PytestPluginManager | ||||||
| ~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|  | @ -909,6 +909,7 @@ class Config: | ||||||
|         self._parser = Parser( |         self._parser = Parser( | ||||||
|             usage=f"%(prog)s [options] [{_a}] [{_a}] [...]", |             usage=f"%(prog)s [options] [{_a}] [{_a}] [...]", | ||||||
|             processopt=self._processopt, |             processopt=self._processopt, | ||||||
|  |             _ispytest=True, | ||||||
|         ) |         ) | ||||||
|         self.pluginmanager = pluginmanager |         self.pluginmanager = pluginmanager | ||||||
|         """The plugin manager handles plugin registration and hook invocation. |         """The plugin manager handles plugin registration and hook invocation. | ||||||
|  | @ -1380,8 +1381,8 @@ class Config: | ||||||
|         """Return configuration value from an :ref:`ini file <configfiles>`. |         """Return configuration value from an :ref:`ini file <configfiles>`. | ||||||
| 
 | 
 | ||||||
|         If the specified name hasn't been registered through a prior |         If the specified name hasn't been registered through a prior | ||||||
|         :py:func:`parser.addini <_pytest.config.argparsing.Parser.addini>` |         :func:`parser.addini <pytest.Parser.addini>` call (usually from a | ||||||
|         call (usually from a plugin), a ValueError is raised. |         plugin), a ValueError is raised. | ||||||
|         """ |         """ | ||||||
|         try: |         try: | ||||||
|             return self._inicache[name] |             return self._inicache[name] | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ from _pytest.config.exceptions import UsageError | ||||||
| from _pytest.deprecated import ARGUMENT_PERCENT_DEFAULT | from _pytest.deprecated import ARGUMENT_PERCENT_DEFAULT | ||||||
| from _pytest.deprecated import ARGUMENT_TYPE_STR | from _pytest.deprecated import ARGUMENT_TYPE_STR | ||||||
| from _pytest.deprecated import ARGUMENT_TYPE_STR_CHOICE | from _pytest.deprecated import ARGUMENT_TYPE_STR_CHOICE | ||||||
|  | from _pytest.deprecated import check_ispytest | ||||||
| 
 | 
 | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|     from typing import NoReturn |     from typing import NoReturn | ||||||
|  | @ -43,8 +44,11 @@ class Parser: | ||||||
|         self, |         self, | ||||||
|         usage: Optional[str] = None, |         usage: Optional[str] = None, | ||||||
|         processopt: Optional[Callable[["Argument"], None]] = None, |         processopt: Optional[Callable[["Argument"], None]] = None, | ||||||
|  |         *, | ||||||
|  |         _ispytest: bool = False, | ||||||
|     ) -> None: |     ) -> None: | ||||||
|         self._anonymous = OptionGroup("custom options", parser=self) |         check_ispytest(_ispytest) | ||||||
|  |         self._anonymous = OptionGroup("custom options", parser=self, _ispytest=True) | ||||||
|         self._groups: List[OptionGroup] = [] |         self._groups: List[OptionGroup] = [] | ||||||
|         self._processopt = processopt |         self._processopt = processopt | ||||||
|         self._usage = usage |         self._usage = usage | ||||||
|  | @ -67,14 +71,14 @@ class Parser: | ||||||
|         :after: Name of another group, used for ordering --help output. |         :after: Name of another group, used for ordering --help output. | ||||||
| 
 | 
 | ||||||
|         The returned group object has an ``addoption`` method with the same |         The returned group object has an ``addoption`` method with the same | ||||||
|         signature as :py:func:`parser.addoption |         signature as :func:`parser.addoption <pytest.Parser.addoption>` but | ||||||
|         <_pytest.config.argparsing.Parser.addoption>` but will be shown in the |         will be shown in the respective group in the output of | ||||||
|         respective group in the output of ``pytest. --help``. |         ``pytest. --help``. | ||||||
|         """ |         """ | ||||||
|         for group in self._groups: |         for group in self._groups: | ||||||
|             if group.name == name: |             if group.name == name: | ||||||
|                 return group |                 return group | ||||||
|         group = OptionGroup(name, description, parser=self) |         group = OptionGroup(name, description, parser=self, _ispytest=True) | ||||||
|         i = 0 |         i = 0 | ||||||
|         for i, grp in enumerate(self._groups): |         for i, grp in enumerate(self._groups): | ||||||
|             if grp.name == after: |             if grp.name == after: | ||||||
|  | @ -334,9 +338,17 @@ class Argument: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class OptionGroup: | class OptionGroup: | ||||||
|  |     """A group of options shown in its own section.""" | ||||||
|  | 
 | ||||||
|     def __init__( |     def __init__( | ||||||
|         self, name: str, description: str = "", parser: Optional[Parser] = None |         self, | ||||||
|  |         name: str, | ||||||
|  |         description: str = "", | ||||||
|  |         parser: Optional[Parser] = None, | ||||||
|  |         *, | ||||||
|  |         _ispytest: bool = False, | ||||||
|     ) -> None: |     ) -> None: | ||||||
|  |         check_ispytest(_ispytest) | ||||||
|         self.name = name |         self.name = name | ||||||
|         self.description = description |         self.description = description | ||||||
|         self.options: List[Argument] = [] |         self.options: List[Argument] = [] | ||||||
|  | @ -346,9 +358,9 @@ class OptionGroup: | ||||||
|         """Add an option to this group. |         """Add an option to this group. | ||||||
| 
 | 
 | ||||||
|         If a shortened version of a long option is specified, it will |         If a shortened version of a long option is specified, it will | ||||||
|         be suppressed in the help. addoption('--twowords', '--two-words') |         be suppressed in the help. ``addoption('--twowords', '--two-words')`` | ||||||
|         results in help showing '--two-words' only, but --twowords gets |         results in help showing ``--two-words`` only, but ``--twowords`` gets | ||||||
|         accepted **and** the automatic destination is in args.twowords. |         accepted **and** the automatic destination is in ``args.twowords``. | ||||||
|         """ |         """ | ||||||
|         conflict = set(optnames).intersection( |         conflict = set(optnames).intersection( | ||||||
|             name for opt in self.options for name in opt.names() |             name for opt in self.options for name in opt.names() | ||||||
|  |  | ||||||
|  | @ -88,11 +88,11 @@ def pytest_addoption(parser: "Parser", pluginmanager: "PytestPluginManager") -> | ||||||
|         files situated at the tests root directory due to how pytest |         files situated at the tests root directory due to how pytest | ||||||
|         :ref:`discovers plugins during startup <pluginorder>`. |         :ref:`discovers plugins during startup <pluginorder>`. | ||||||
| 
 | 
 | ||||||
|     :param _pytest.config.argparsing.Parser parser: |     :param pytest.Parser parser: | ||||||
|         To add command line options, call |         To add command line options, call | ||||||
|         :py:func:`parser.addoption(...) <_pytest.config.argparsing.Parser.addoption>`. |         :py:func:`parser.addoption(...) <pytest.Parser.addoption>`. | ||||||
|         To add ini-file values call :py:func:`parser.addini(...) |         To add ini-file values call :py:func:`parser.addini(...) | ||||||
|         <_pytest.config.argparsing.Parser.addini>`. |         <pytest.Parser.addini>`. | ||||||
| 
 | 
 | ||||||
|     :param _pytest.config.PytestPluginManager pluginmanager: |     :param _pytest.config.PytestPluginManager pluginmanager: | ||||||
|         pytest plugin manager, which can be used to install :py:func:`hookspec`'s |         pytest plugin manager, which can be used to install :py:func:`hookspec`'s | ||||||
|  | @ -193,7 +193,7 @@ def pytest_load_initial_conftests( | ||||||
| 
 | 
 | ||||||
|     :param _pytest.config.Config early_config: The pytest config object. |     :param _pytest.config.Config early_config: The pytest config object. | ||||||
|     :param List[str] args: Arguments passed on the command line. |     :param List[str] args: Arguments passed on the command line. | ||||||
|     :param _pytest.config.argparsing.Parser parser: To add command line options. |     :param pytest.Parser parser: To add command line options. | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,6 +13,8 @@ from _pytest.config import hookimpl | ||||||
| from _pytest.config import hookspec | from _pytest.config import hookspec | ||||||
| from _pytest.config import main | from _pytest.config import main | ||||||
| from _pytest.config import UsageError | from _pytest.config import UsageError | ||||||
|  | from _pytest.config.argparsing import OptionGroup | ||||||
|  | from _pytest.config.argparsing import Parser | ||||||
| from _pytest.debugging import pytestPDB as __pytestPDB | from _pytest.debugging import pytestPDB as __pytestPDB | ||||||
| from _pytest.fixtures import _fillfuncargs | from _pytest.fixtures import _fillfuncargs | ||||||
| from _pytest.fixtures import fixture | from _pytest.fixtures import fixture | ||||||
|  | @ -103,8 +105,10 @@ __all__ = [ | ||||||
|     "Metafunc", |     "Metafunc", | ||||||
|     "Module", |     "Module", | ||||||
|     "MonkeyPatch", |     "MonkeyPatch", | ||||||
|  |     "OptionGroup", | ||||||
|     "Package", |     "Package", | ||||||
|     "param", |     "param", | ||||||
|  |     "Parser", | ||||||
|     "PytestAssertRewriteWarning", |     "PytestAssertRewriteWarning", | ||||||
|     "PytestCacheWarning", |     "PytestCacheWarning", | ||||||
|     "PytestCollectionWarning", |     "PytestCollectionWarning", | ||||||
|  |  | ||||||
|  | @ -14,12 +14,12 @@ from _pytest.pytester import Pytester | ||||||
| 
 | 
 | ||||||
| @pytest.fixture | @pytest.fixture | ||||||
| def parser() -> parseopt.Parser: | def parser() -> parseopt.Parser: | ||||||
|     return parseopt.Parser() |     return parseopt.Parser(_ispytest=True) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class TestParser: | class TestParser: | ||||||
|     def test_no_help_by_default(self) -> None: |     def test_no_help_by_default(self) -> None: | ||||||
|         parser = parseopt.Parser(usage="xyz") |         parser = parseopt.Parser(usage="xyz", _ispytest=True) | ||||||
|         pytest.raises(UsageError, lambda: parser.parse(["-h"])) |         pytest.raises(UsageError, lambda: parser.parse(["-h"])) | ||||||
| 
 | 
 | ||||||
|     def test_custom_prog(self, parser: parseopt.Parser) -> None: |     def test_custom_prog(self, parser: parseopt.Parser) -> None: | ||||||
|  | @ -90,13 +90,13 @@ class TestParser: | ||||||
|         assert groups_names == list("132") |         assert groups_names == list("132") | ||||||
| 
 | 
 | ||||||
|     def test_group_addoption(self) -> None: |     def test_group_addoption(self) -> None: | ||||||
|         group = parseopt.OptionGroup("hello") |         group = parseopt.OptionGroup("hello", _ispytest=True) | ||||||
|         group.addoption("--option1", action="store_true") |         group.addoption("--option1", action="store_true") | ||||||
|         assert len(group.options) == 1 |         assert len(group.options) == 1 | ||||||
|         assert isinstance(group.options[0], parseopt.Argument) |         assert isinstance(group.options[0], parseopt.Argument) | ||||||
| 
 | 
 | ||||||
|     def test_group_addoption_conflict(self) -> None: |     def test_group_addoption_conflict(self) -> None: | ||||||
|         group = parseopt.OptionGroup("hello again") |         group = parseopt.OptionGroup("hello again", _ispytest=True) | ||||||
|         group.addoption("--option1", "--option-1", action="store_true") |         group.addoption("--option1", "--option-1", action="store_true") | ||||||
|         with pytest.raises(ValueError) as err: |         with pytest.raises(ValueError) as err: | ||||||
|             group.addoption("--option1", "--option-one", action="store_true") |             group.addoption("--option1", "--option-one", action="store_true") | ||||||
|  | @ -188,7 +188,7 @@ class TestParser: | ||||||
|             elif option.type is str: |             elif option.type is str: | ||||||
|                 option.default = "world" |                 option.default = "world" | ||||||
| 
 | 
 | ||||||
|         parser = parseopt.Parser(processopt=defaultget) |         parser = parseopt.Parser(processopt=defaultget, _ispytest=True) | ||||||
|         parser.addoption("--this", dest="this", type=int, action="store") |         parser.addoption("--this", dest="this", type=int, action="store") | ||||||
|         parser.addoption("--hello", dest="hello", type=str, action="store") |         parser.addoption("--hello", dest="hello", type=str, action="store") | ||||||
|         parser.addoption("--no", dest="no", action="store_true") |         parser.addoption("--no", dest="no", action="store_true") | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue