Skip to content

Accept type expressions in Parser.addini(type=...)#14751

Open
Pierre-Sassoulas wants to merge 2 commits into
pytest-dev:mainfrom
Pierre-Sassoulas:addini-type-expressions
Open

Accept type expressions in Parser.addini(type=...)#14751
Pierre-Sassoulas wants to merge 2 commits into
pytest-dev:mainfrom
Pierre-Sassoulas:addini-type-expressions

Conversation

@Pierre-Sassoulas

Copy link
Copy Markdown
Member

Prior refactor in order to be able to do #14692 cleanly.

addini now accepts plain Python types (str, bool, int, float) and unions of them (e.g. int | str) for its type argument, in addition to the existing string tags, as proposed by bluetech in #14675.

@Pierre-Sassoulas Pierre-Sassoulas added type: enhancement new feature or API change, should be merged into features branch type: refactoring internal improvements to the code skip news used on prs to opt out of the changelog requirement labels Jul 21, 2026
@Pierre-Sassoulas Pierre-Sassoulas removed the skip news used on prs to opt out of the changelog requirement label Jul 21, 2026
@psf-chronographer psf-chronographer Bot added the bot:chronographer:provided (automation) changelog entry is part of PR label Jul 21, 2026
Pierre-Sassoulas and others added 2 commits July 21, 2026 21:09
Pure refactor: move the ini/toml mode dispatch into a helper method, in
preparation for calling it per union member when addini grows support
for union types.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
addini now accepts plain Python types (str, bool, int, float) and
unions of them (e.g. `int | str`) for its `type` argument, in addition
to the existing string tags, as proposed by bluetech in pytest-dev#14675.

A union means the option accepts a value of any of its member types:
getini tries each member in order and returns the first that accepts
the value. In TOML config the native value may be of any member type,
and string-based formats (INI files, -o overrides) coerce it to the
first member that accepts it. Internally union types are normalized to
a tuple of the existing string tags, reusing the per-tag coercion;
single-tag registration and lookup are unchanged.

An invalid `type` argument raises ValueError instead of asserting,
since it is user (plugin) provided, and registering a union type
without an explicit default also raises ValueError instead of silently
defaulting to None.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Pierre-Sassoulas
Pierre-Sassoulas force-pushed the addini-type-expressions branch from d9a3d92 to 412e21b Compare July 21, 2026 19:10

@bluetech bluetech left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM!

(As I mentioned in the previous comment, I also think Literal support would be nice for some configs, but that can be done separately).

plain Python type.
"""
if isinstance(type_, str) and type_ in _INI_TYPE_TAGS:
return cast("_IniTypeTag", type_)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the string type needed here (i.e. does replacing with _IniTypeTag not work)?

FILE_OR_DIR = "file_or_dir"

#: The string tags accepted by :meth:`Parser.addini` for its ``type`` argument.
_IniTypeTag = Literal[

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add : TypeAlias to these, then it will be automatically upgraded to type statement once that's available.

if default is NOTSET:
default = get_ini_default_for_type(type)
if isinstance(ini_type, tuple):
# A union has no unambiguous implicit default; require an

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the exception message is clear enough that the comment is redundant.

@bluetech

Copy link
Copy Markdown
Member

I think this is a simple and clear enough extension to the existing mechanism that even if we ever go with something more elaborate like @RonnyPfannschmidt proposed, it won't be a bother.

Comment on lines +228 to +230
type: _IniTypeTag
| type[bool | int | float | str]
| types.UnionType

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be written more type-safely as

type: _IniTypeTag | TypeForm[bool | int | float | str] | None = None,

where TypeForm is imported from typing_extensions under if TYPE_CHECKING (added in Python 3.15). It seems to work as intended in mypy at least.

@RonnyPfannschmidt

Copy link
Copy Markdown
Member

It's not blocking my ever evading elaboration 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided (automation) changelog entry is part of PR type: enhancement new feature or API change, should be merged into features branch type: refactoring internal improvements to the code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants