-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Allow int for truncation_limit_lines and truncation_limit_chars in TOML
#14692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Pierre-Sassoulas
wants to merge
3
commits into
pytest-dev:main
Choose a base branch
from
Pierre-Sassoulas:fix-truncation-limit-int-14675
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| The :confval:`truncation_limit_lines` and :confval:`truncation_limit_chars` configuration options now accept integer values in TOML configuration files, while still accepting strings for backward compatibility. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| :func:`parser.addini <pytest.Parser.addini>` now also accepts plain Python types (``str``, ``bool``, ``int``, ``float``) and unions of them (for example ``int | str``) for its ``type`` argument, in addition to the existing string tags. A union accepts a value of any of its member types. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,10 +7,15 @@ | |||||||||
| import os | ||||||||||
| import sys | ||||||||||
| import textwrap | ||||||||||
| import types | ||||||||||
| from typing import Any | ||||||||||
| from typing import cast | ||||||||||
| from typing import final | ||||||||||
| from typing import get_args | ||||||||||
| from typing import get_origin | ||||||||||
| from typing import Literal | ||||||||||
| from typing import NoReturn | ||||||||||
| from typing import Union | ||||||||||
|
|
||||||||||
| from .exceptions import UsageError | ||||||||||
| import _pytest._io | ||||||||||
|
|
@@ -20,6 +25,57 @@ | |||||||||
|
|
||||||||||
| FILE_OR_DIR = "file_or_dir" | ||||||||||
|
|
||||||||||
| #: The string tags accepted by :meth:`Parser.addini` for its ``type`` argument. | ||||||||||
| #: Keep in sync with _INI_TYPE_TAGS. | ||||||||||
| _IniTypeTag = Literal[ | ||||||||||
| "string", "paths", "pathlist", "args", "linelist", "bool", "int", "float" | ||||||||||
| ] | ||||||||||
|
|
||||||||||
| #: An ini option type, as stored internally after normalization: either a | ||||||||||
| #: single tag, or a tuple of tags meaning "accept a value of any of these | ||||||||||
| #: types" (e.g. ``("int", "string")``, normalized from ``int | str``). | ||||||||||
| IniType = _IniTypeTag | tuple[_IniTypeTag, ...] | ||||||||||
|
|
||||||||||
| #: Runtime list tags accepted by :meth:`Parser.addini` for its ``type`` argument. | ||||||||||
| #: Keep in sync with _IniTypeTag. | ||||||||||
| _INI_TYPE_TAGS: tuple[str, ...] = ( | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| "string", | ||||||||||
| "paths", | ||||||||||
| "pathlist", | ||||||||||
| "args", | ||||||||||
| "linelist", | ||||||||||
| "bool", | ||||||||||
| "int", | ||||||||||
| "float", | ||||||||||
| ) | ||||||||||
|
|
||||||||||
| #: Maps the plain Python types accepted by :meth:`Parser.addini` for its | ||||||||||
| #: ``type`` argument to the equivalent string tag. | ||||||||||
| _INI_TYPE_TO_TAG: dict[type, _IniTypeTag] = { | ||||||||||
| str: "string", | ||||||||||
| bool: "bool", | ||||||||||
| int: "int", | ||||||||||
| float: "float", | ||||||||||
| } | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def _ini_type_to_tag(name: str, type_: object) -> _IniTypeTag: | ||||||||||
| """Normalize one member of an `addini(type=...)` argument to a string tag. | ||||||||||
|
|
||||||||||
| Raise ValueError for anything that is neither a known tag nor a supported | ||||||||||
| plain Python type. | ||||||||||
| """ | ||||||||||
| if isinstance(type_, str): | ||||||||||
| if type_ in _INI_TYPE_TAGS: | ||||||||||
| return cast("_IniTypeTag", type_) | ||||||||||
| elif isinstance(type_, type) and type_ in _INI_TYPE_TO_TAG: | ||||||||||
| return _INI_TYPE_TO_TAG[type_] | ||||||||||
| raise ValueError( | ||||||||||
| f"invalid type for ini option {name!r}: {type_!r} (expected one of " | ||||||||||
| f"{', '.join(repr(tag) for tag in _INI_TYPE_TAGS)}, one of the types " | ||||||||||
| "str, bool, int, float, or a union of these types such as `int | str`)" | ||||||||||
| ) | ||||||||||
|
|
||||||||||
|
|
||||||||||
| @final | ||||||||||
| class Parser: | ||||||||||
|
|
@@ -54,7 +110,7 @@ def __init__( | |||||||||
| file_or_dir_arg = self.optparser.add_argument(FILE_OR_DIR, nargs="*") | ||||||||||
| file_or_dir_arg.completer = filescompleter # type: ignore | ||||||||||
|
|
||||||||||
| self._inidict: dict[str, tuple[str, str, Any]] = {} | ||||||||||
| self._inidict: dict[str, tuple[str, IniType, Any]] = {} | ||||||||||
| # Maps alias -> canonical name. | ||||||||||
| self._ini_aliases: dict[str, str] = {} | ||||||||||
|
|
||||||||||
|
|
@@ -182,9 +238,9 @@ def addini( | |||||||||
| self, | ||||||||||
| name: str, | ||||||||||
| help: str, | ||||||||||
| type: Literal[ | ||||||||||
| "string", "paths", "pathlist", "args", "linelist", "bool", "int", "float" | ||||||||||
| ] | ||||||||||
| type: _IniTypeTag | ||||||||||
| | type[bool | int | float | str] | ||||||||||
| | types.UnionType | ||||||||||
| | None = None, | ||||||||||
| default: Any = NOTSET, | ||||||||||
| *, | ||||||||||
|
|
@@ -210,6 +266,18 @@ def addini( | |||||||||
|
|
||||||||||
| The ``float`` and ``int`` types. | ||||||||||
|
|
||||||||||
| For the scalar types, the plain Python type may be passed instead | ||||||||||
| of the string tag: ``str``, ``bool``, ``int`` and ``float`` (for | ||||||||||
| example ``type=int``). A union of these types accepts a value of | ||||||||||
| any of its members, for example ``int | str``. In TOML | ||||||||||
| configuration files the value may then be any of the member types; | ||||||||||
| string-based formats (INI files, ``-o`` overrides) coerce it to the | ||||||||||
| first member that accepts it. | ||||||||||
|
|
||||||||||
| .. versionadded:: 9.1 | ||||||||||
|
|
||||||||||
| Passing a type expression such as ``int`` or ``int | str``. | ||||||||||
|
|
||||||||||
| For ``paths`` and ``pathlist`` types, they are considered relative to the config-file. | ||||||||||
| In case the execution is happening without a config-file defined, | ||||||||||
| they will be considered relative to the current working directory (for example with ``--override-ini``). | ||||||||||
|
|
@@ -233,23 +301,19 @@ def addini( | |||||||||
| The value of configuration keys can be retrieved via a call to | ||||||||||
| :py:func:`config.getini(name) <pytest.Config.getini>`. | ||||||||||
| """ | ||||||||||
| assert type in ( | ||||||||||
| None, | ||||||||||
| "string", | ||||||||||
| "paths", | ||||||||||
| "pathlist", | ||||||||||
| "args", | ||||||||||
| "linelist", | ||||||||||
| "bool", | ||||||||||
| "int", | ||||||||||
| "float", | ||||||||||
| ) | ||||||||||
| ini_type: IniType | ||||||||||
| if type is None: | ||||||||||
| type = "string" | ||||||||||
| ini_type = "string" | ||||||||||
| elif get_origin(type) in (Union, types.UnionType): | ||||||||||
| ini_type = tuple( | ||||||||||
| _ini_type_to_tag(name, member) for member in get_args(type) | ||||||||||
| ) | ||||||||||
| else: | ||||||||||
| ini_type = _ini_type_to_tag(name, type) | ||||||||||
| if default is NOTSET: | ||||||||||
| default = get_ini_default_for_type(type) | ||||||||||
| default = get_ini_default_for_type(name, ini_type) | ||||||||||
|
|
||||||||||
| self._inidict[name] = (help, type, default) | ||||||||||
| self._inidict[name] = (help, ini_type, default) | ||||||||||
|
|
||||||||||
| for alias in aliases: | ||||||||||
| if alias in self._inidict: | ||||||||||
|
|
@@ -261,16 +325,18 @@ def addini( | |||||||||
| self._ini_aliases[alias] = name | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def get_ini_default_for_type( | ||||||||||
| type: Literal[ | ||||||||||
| "string", "paths", "pathlist", "args", "linelist", "bool", "int", "float" | ||||||||||
| ], | ||||||||||
| ) -> Any: | ||||||||||
| def get_ini_default_for_type(name: str, type: IniType) -> Any: | ||||||||||
| """ | ||||||||||
| Used by addini to get the default value for a given config option type, when | ||||||||||
| default is not supplied. | ||||||||||
| """ | ||||||||||
| if type in ("paths", "pathlist", "args", "linelist"): | ||||||||||
| if isinstance(type, tuple): | ||||||||||
| # A union has no unambiguous implicit default; require an explicit one. | ||||||||||
| raise ValueError( | ||||||||||
| f"ini option {name!r} has a union type, which has no implicit " | ||||||||||
| "default; pass an explicit `default` to `addini`" | ||||||||||
| ) | ||||||||||
| elif type in ("paths", "pathlist", "args", "linelist"): | ||||||||||
| return [] | ||||||||||
| elif type == "bool": | ||||||||||
| return False | ||||||||||
|
|
||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.