as per https://www.python.org/dev/peps/pep-0518/#specification
the file has a section for tools using the pypi name for the tool,
so this is the one file where we can properly and in a supported way put metadata
i propose adding support asap and deprecating the other config files for the 3.x series so we can possibly remove support starting with the 4.x series
Big -1 on deprecating pytest.ini if you also suggest that.
My config files are pretty big, which is why I want to keep them in their own file rather than stuffing everything into one - line count:
18 .coveragerc
59 .flake8
13 .pydocstylerc
69 .pylintrc
245 tox.ini
41 pytest.ini
i see, good point!
i change my proposal to deprecating all files other than pytest.ini and pyproject.toml
Any plans on moving this forward? π
@hynek yes, but no time/volunteer
Hey guys, I gave it a go in #3686. It adds support for pyproject.toml but doesn't deprecate anything.
Any ideas on how we the file would look like? #3686 was an attempt made by @tadeoos, but @RonnyPfannschmidt mentioned that we should take advantage of the additional layers offered by TOML.
I suggest we focus on the file format first, then after a consensus move to the API to get to that file format.
My quick take on this is that we don't need many sections other than separating built-in options from those defined by plugins. For brevity I think built-options could go to a root tool.pytest table, and plugin options in sub-tables named after the plugin.
Quick example:
[tool.pytest]
junit_family = "xunit2"
doctest_encoding = "UTF-8"
[tool.pytest.qt]
qt_api = "qt5"
[tool.pytest.timeout]
timeout = 10
[tool.pytest.xprocess]
timeout = 10
This avoids ini-options from different plugins to clashing.
that would intermix pytest and plugin tables in the most unforetunate manner,
tool.pytest.x nests inside tool.pytest
plugins should use tool.pytest_x, matching the distribution name with dashes replaced by underscore perhaps
the real problem isnt the new config file, the real problem is layering, integration of the old config options and transition of the apis
that would intermix pytest and plugin tables in the most unforetunate manner,
Why would that be a problem?
The real problem isnt the new config file, the real problem is layering, integration of the old config options and transition of the apis
Oh I know, but I thought the discussion should start from the file format first. I'm well aware that the hard work will be the integration and backward compatibility. π
Right, @nicodemus's example is equivalent to
[tool.pytest]
junit_family = "xunit2"
doctest_encoding = "UTF-8"
qt = { qt_api = "qt5" }
timeout = { timeout = 10 }
xprocess = { timeout = 10 }
If you wanted to avoid collisions you could use [tool.pytest.plugin.pytest-whatever], but that seems like it might be excessive, given that [tool.pytest-whatever] is already available.
with dashes replaced by underscore perhaps
Dashes are fine in toml keys, so if packages want to use [tool.pytest-whatever] then that's fine.
@nicoddemus i believe that without the integration strategy, we will end up with a massive mess
right now config initialization is pretty much fundamentally broken to begin with
For illustration:
[tool.pytest]
junit_family = "xunit2"
doctest_encoding = "UTF-8"
[tool.pytest-qt]
qt_api = "qt5"
[tool.pytest-timeout]
timeout = 10
[tool.pytest-xprocess]
timeout = 10
i believe that without the integration strategy, we will end up with a massive mess
"massive mess" on the file format or the code to support the file format in the end? We can always can come back to the drawing board if we can't find a clean way to implement the desired file format.
Or do you want to change the discussion from the file format over to the API/integration?
the format is easy, the integration/semantics are __hard__
I would also like to see this feature added.
What does the approach taken by tox to have a legacy session inside the toml file where it contains a plain string with the current pytest.ini contents? This would at least allow people to move their configuration there, while we try to brainstorm how to move this forward.
That one would be good, we could also support a mapping of options to strings or lists as the legacy value to take advantage of the file format for Syntax, which may be a help to the desired semantics
we could also support a mapping of options to strings or lists as the legacy value to take advantage of the file format for Syntax, which may be a help to the desired semantics
Interesting, care to elaborate, perhaps with examples?
Format strings come to mind, and native lists
I won't make examples as I'm currently afk
[tool.pytest.LEGACY]
addopts = ["-p", "test"]
or
[tool.pytest]
LEGACY = """
addopts = -p test
"""
if a multiline string is used, we should allow a missing [pytest]
if a mapping is used, the type of each value should be enforced to exactly match whats used/declared (to avoid having to be unreasonably smart about the transformations in a format thats only supposed to help with transitions
(perhaps we should not support the mapping form to begin with)
will your example be able to support an hybride version of LEGACY flags and new one?
Or we should migrate everything in order to remove LEGACY completely ?
@NargiT personally, i'd aim for big bang changes there
Big bang is good for me as long as the refactoring is easy enough to not waste to much time
I personally like
[tool.pytest.LEGACY]
addopts = ["-p", "test"]
Because then we have the more explicit data types to use.
Neverthless, we should discuss the pain points, which I think is mainly that the API to declare/get options don't have any extra context other than the option name:
parser.addini(name, help, ...)config.getini(name, default)This makes it hard for those methods to know if who is asking for the option's value is pytest-qt or pytest-timeout (for example).
Any ideas to overcome this?
I have some, none of which I really like:
Create proxy objects to config which are aware of the context where they will be used, and pass that along to the hooks which give access to the config object, instead of the actual config object.
Pros:
ini or toml) without changes.toml, without nameclashes.Cons:
pluggy for that happen.conftest.py files.Introduce an optional parameter to config.addini and config.getini, context: it means the context in which the option will reside in configuration files. For example:
parser.addini('qt_api', ..., context='pytest-qt')
parser.getini('qt_api', default='qt5', context='pytest-qt')
Then this would translate to:
[pytest]
pytest-qt.qt_api = "qt5"
Or:
[tool.pytest]
[tool.pytest-qt]
qt_api = "qt5"
context=None means a flat option, exactly like today. Also, if addini receives a context, every getini call would also need one.
Pros:
api instead of qt_api now (of course there's backward compatibility concerns for the plugin).Cons:
getini is longer to type, now we need to include context in all calls.Longer option names to type in the config files
addini, which would issue a deprecation warning when the "flat" option is used, and indicate the new option automatically:parser.addini('api', ..., context='pytest-qt', legacy='qt_api')
Would emit a PytestDeprecationWarning:
ini option 'qt_api' has been deprecated, use 'pytest-qt.api' from now on.
As I said, I don't like any of the above much, but no other ideas come to mind.
Having said all that, what are the problems with the current .ini format? Here's what I gather:
pyproject.toml.toml would solve the first 4 options nicely and naturally.
The 5th option TBH doesn't seem to be a huge problem in practice: pytest has existed for many years now (eleven?), and plugins have found a way to not step on each other's toes.
If these are the problems we are trying to solve, then perhaps just adopting flat options in the toml format be enough for our needs?
toml
[tool.pytest]
addopts = ["-p", "test"]
qt_api = "qt5"
This has the following real world advantages:
To further mitigate the possibility of plugins nameclashing option names, we could explicitly recomment that they add some unique prefix to the options, like qt_api has used since its inception, and similar to the same recommendation we have for keys in the cache plugin.
im absolutely certain that the cost would be a horrific pain if we simply mulled the addini api to support toml
ini and tomml have different value type models, and i really would prefer declaring the real options in the new system and then declaring how a legacy ini option translates to the new system for a transition period
ini and tomml have different value type models, and i really would prefer declaring the real options in the new system and then declaring how a legacy ini option translates to the new system for a transition period
You mean the addini's type parameter, which supports "pathlist, args, linelist or bool"?
Can you please provide a better description of what are your concerns, and you would like to see (preferably with examples)? I'm sorry, but your description is quite vague to me, so I'm left with guessing.
I won't be able to make a good mockup until next week, I'll put it in a todo
Great, thanks!
@RonnyPfannschmidt gentle ping. π
Thanks for the reminder, unfortunately I am on mobile and about to go to a vocation
i wanted to start with the loggin plugin, but this immeadely made me want to burn the config systme with dire, i'll strill come up with a nomerge pr for the tooling example
I'm a bit concerned about the direction the overall discussion is going (not #5882 in particular per see, I definitely appreciate taking the time to write it up).
My impression is that this would introduce a real complexity to pytest's configuration which I don't think neither users nor plugins need.
It would also mean that users will need to understand the intricacies of the different systems, and plugin authors would have to support both ways to declare options for many years to come. Worse, users wanting to migrate to pyproject.toml would then be at mercy of the authors of the plugins they use (until the plugins support the new way), or fallback to have half the configuration in pytest.ini, the other half in pyproject.toml.
I understand this is far from a simple issue (as other projects are also in the same state), but I would like to further discuss the points I brought up in https://github.com/pytest-dev/pytest/issues/1556#issuecomment-528659962 (which I took a good time to write, would appreciate some thoughtful/elaborate replies to it).
More explicitly, I would like thoughtful/elaborate answers to:
config.addini API?pyproject.toml support in pytest?setup.cfg doesn't, but we would like to have in pytest configuration?I fear the discussion is stalled because it is not clear (at least to me) what problems we are trying to solve, which are the existing pain points, etc. π¬
thanks for calling out the lack of a clear vision, i#ll let this linger in the back of my head a while longer to come up with good answers to the points
- What is the problem which we would be solving by adding support for
pyproject.tomlsupport in pytest?
Project directories these days are stuffed with config files of various formats/conventions: requirements.txt, mypy.ini, Pipfile, .style.yapf, tox.ini, pytest.ini, etc... . These add a lot of noise to the project directories and quite some mental overhead when you work on them. This is not a big deal if you maintain a few projects, but it's taxing if you work on many projects simultaneously. To me it would be a great relief to combine them in pyproject.toml and use the same config convention for every tool.
In the long run the whole Python ecosystem will benefit from a standardized config system and I guess the toml proposal is the first one which is powerful enough to succeed. I'm cheering for every major Python tool to jump on the PEP-518 wagon. ;-)
That's a lovely idea, but we have to give ourselves an user lens so the feature removes user problems instead of shifting or piling them
if we introduce toml support, then I'd like to unify configuration and configuration sources in a way that makes usage better
until we actually have a sensible idea for that transition its preferable to keep the current system or just enable pytest. ini content in a legacy multiline item
I am following this issue for some time so I would like to give my input on this.
I am currently maintaining several Python/Django project and I try to use the same skeleton for all of them. These projects are using several tools:
Each tool has it's own configuration system, some used it's own format (coverage) while others used setup.cfg. Black was actually the first one that forced me to create a pyproject.toml file and what I noticed is that over 2018-2019 several of the other projects are implementing pyproject.toml support:
So far, pre-commit is the only one that didn't jump into the pyproject.toml bandwagon but giving that pre-commit is a language-agnostic tool I think that decision makes sense. But as you can see, there is a clear trend in the Python community to support the pyproject.toml format.
Having a unified configuration format/file (and backed by a PEP nonetheless) is beneficial for the Python community and given that some projects are not supporting setup.cfg at all (Black) the pyproject.toml seems to be way to go.
Thanks everyone so far.
I think we can all agree that moving to pyproject.toml to reduce the number of files is a good idea, so I believe this out of the table for now.
@canassa
Thanks for the links, I was wondering which projects have made the switch and how they did it.
It seems isort just moved their flat options over to pyproject.toml.
For coverage I couldn't find the PR or the docs (but I didn't search much actually).
@RonnyPfannschmidt
if we introduce toml support, then I'd like to unify configuration and configuration sources...
What do you mean "configuration sources", the various files supported currently?
... in a way that makes usage better
Usage better for who? Users or plugin authors?
If possible it would be nice to enumerate the current problems (both in API and configuration), rather than try to come up with a solution, because it still not crystal clear what the current problems are to me.
From my previous comment, I've listed this as the current problems:
What else can you add to this list?
You also mention that the current configuration API is a mess... can you provide a clear list of those problems?
The community is pushing to have a pyproject.toml in the same format as a pytest.ini, which they think is reasonable.
@RonnyPfannschmidt seems to think this is problematic, but why this is problematic doesn't seem to be clear yet.
If we are going to stall this, it would be good to list the exactl reasons why this is stalled, so we can point people to the reasons when they wonder why pytest doesn't support pyproject.toml yet.
I was wondering which projects have made the switch and how they did it.
https://github.com/flying-sheep/awesome-python-packaging lists projects which support it.
Thanks @hugovk!
Just to clarify: PEP 518 is about build isolation for packaging tools, and incidentally defines the pyproject.toml file. It is not a spec for all Python dev tools to use the file (but mentions that they can do it β PEP authors expected packaging-related tools to do so, not necessarily all dev tools). Having a toolβs option in pyproject.toml is an emerging community practice, but itβs not accurate to say itβs backed by a PEP.
@RonnyPfannschmidt
if we introduce toml support, then I'd like to unify configuration and configuration sources...
What do you mean "configuration sources", the various files supported currently?
currently we have cli options and ini entries as configuration sources,
those have distinct type systems with distinct capabilities
in many plug-ins and pytest core we try to mix and coerce those manually
... in a way that makes usage better
if we add toml in a sane way, it will need yet another type system, suddenly everyone would have to juggle 3 systems, when 2 of them are already quite a mess
Usage better for who? Users or plugin authors?
"both" this one is tricky
If possible it would be nice to enumerate _the current problems_ (both in API and configuration), rather than try to come up with a solution, because it still not crystal clear what the current problems are to me.
a reasonably exhaustive listing will need a while
From my previous comment, I've listed this as the current problems:
1. No proper unicode support. 2. Has some weird escaping rules. 3. Only supports strings and list of strings as values. 4. Flat option names.What else can you add to this list?
see above for a startYou also mention that the current configuration API is a mess... can you provide a clear list of those problems?
ditoThe community is pushing to have a
pyproject.tomlin the same format as apytest.ini, which they think is reasonable.@RonnyPfannschmidt seems to think this is problematic, but why this is problematic doesn't seem to be clear yet.
the key issues i currently consider a problem are name-spacing and conflicts,
those are indeed not things you see day2day, but when you see them, you certainly wish you didnt
If we are going to stall this, it would be good to list the exactl reasons why this is stalled, so we can point people to the reasons when they wonder why pytest doesn't support
pyproject.tomlyet.
its going to take time to to make the "exact"
but i believe its fair to say that we currently have no idea how to do it good, and we don't want to regret doing it really horrible unfixable
Thanks @RonnyPfannschmidt
currently we have cli options and ini entries as configuration sources,
those have distinct type systems with distinct capabilities
I agree completely, but I believe this problem is orthogonal to pyproject.toml support, is it not?
I mean, I believe the question in most people's mind thinking about this (me included) is what's the problem with adding pyproject.toml as another configuration file format, with same capabilities as pytest.ini today. By itself this would solve a number of problems already (encoding, weird escaping rules, sane syntax, etc).
if we add toml in a sane way, it will need yet another type system, suddenly everyone would have to juggle 3 systems, when 2 of them are already quite a mess
But why would the API need another type system?
Let me elaborate:
Currently we support a few data types in configuration files:
pyproject.toml would work just as well for those.
TOML has more data types, but it seems to me adding support for those later wouldn't change the support we have for the existing ones.
My feeling is that we could add support for TOML, restricting for the same types we currently support for pytest.ini and other configuration files, without changing much of the (bad) APIs we have today.
Later, we can always improve the API (by deprecations/refactorings etc).
a reasonably exhaustive listing will need a while
No need to be exhaustive, but it would be nice to get a list started. π
the key issues i currently consider a problem are name-spacing and conflicts,
those are indeed not things you see day2day, but when you see them, you certainly wish you didnt
Indeed, and name-spacing/conflicts is a problem, but to solve that we have to either:
pytest.ini, so plugins are less encourarged to support it, and so on.For an examples of the later:
# existing API
parser.addini("junit_suite_name", ...)
# implicit context using strings:
parser.addini("junit.suite_name", ...) # this becomes an option "suite_name" under "junit" table, which its a child of [tool.pytest]
# explicit context using strings:
parser.addini(Context("junit", "suite_name"), ...) # same as above
(To be clear: just trying to adress the name-spacing problem here)
All the above have the advantage of being backward compatible.
but i believe its fair to say that we currently have no idea how to do it good, and we don't want to regret doing it really horrible unfixable
Sure, I agree with that, but my point in the previous post is explaining the problems and get them clearly defined, not getting to the solution.
i had a few nights of good sleep, and figured that we can have a good start with just
having something like
[tool.pytest.ini_options]
some_name = "coercible string or coercible toml type"
with clear documentation that this subkey is to enable people to use the single config file even tho pytest itself didn't design a proper type system/integration story for first class toml support
currently i'd like to avoid/defer designing a proper toml type integration - and i certainly want to avoid letting the ini concepts bleed into it
Thanks @RonnyPfannschmidt,
That looks reasonable, but I assume you understand that this:
[tool.pytest]
some_name = "coercible string or coercible toml type"
Might be problematic in the future, correct? Could you elaborate what are your concerns?
Perhaps (and I'm guessing here) you see something like the below might be a possibility in the future?
[tool.pytest.core]
addopts = "-x"
[tool.pytest.timeout]
timeout = 10
[tool.pytest.qt]
api = "pyside2"
@nicoddemus that's why i choose the ini_options subkey, that subkey will be reserved by pytest core to map ini options until the real story is happening
we should bike-shed the key naming a bit, and then take a look at making it work for the legacy transfer
if we find a mistake in that when sorting out the details about the real story we will handle it at that point, i wont speculate atm
I see, thanks. This approach sounds reasonable, and has the advantage to be trivial to understand and port.
I'm OK with [tool.pytest.ini_options]. I think all options from the current config map directly to builtin TOML types, correct?
as far as i can tell yes, we need to take a look if we want to support coercion or just expect some minimal transforms on the user
im inclined to opt for starting without built-in coercion and just expecting users to do the transforms (but also leaving it open to the community to provide a pr with coercion)
Currently the signature for addini is:
def addini(self, name, help, type=None, default=None):
"""
...
:type: type of the variable, can be ``pathlist``, ``args``, ``linelist``
or ``bool``.
...
"""
So we should not do any coercion, in other words, the user calling config.getini shouldn't care if the config came from pytest.ini or pyproject.toml, it should return the exact same value and type.
Plugin authors make the coercion themselves, for example:
if timeout is None:
ini = config.getini("timeout")
if ini:
timeout = _validate_timeout(ini, "config file")
So the [tool.pytest.ini_options] should in fact convert some types to str for compatibility (which makes the ini_options section even more of a good idea).
The example above also highlights the differences between the config and command-line API (which does type-coercion), as you mentioned before.
Now that we have a clearer way forward, I'm tentatively putting this on the roadmap for 5.5. π
Here is the awesome-pyproject list. It would be helpful if and when pytest supports pyproject.toml to notify the list maintainer or submitting a PR to update the list indicating that pytest supports the file now. Just FYI. :)
Have we considered a plugin namespace to clean things up?
[tool.pytest]
addopts = "-x"
[tool.pytest.plugins.timeout]
timeout = 10
[tool.pytest.plugins.qt]
api = "pyside2"
@ofek we have not considered any completely new structure, as we yet have to figure how we want to unify arguments from clie, options from ini files and data from well structured toml data
we also haven't gotten't around investigating how it would actually be used - and i haven't found time to do more on my proposed api
so for now we are just going to support a legacy ini key where ini options can be put instead of the other files, better integration will come later with time or working external proposals
Most helpful comment
Now that we have a clearer way forward, I'm tentatively putting this on the roadmap for 5.5. π