-
-
Notifications
You must be signed in to change notification settings - Fork 447
[WIP] Initial toml support #699
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
Conversation
@RazerM Thanks for all of this! :) I'm reluctant to add this code to the heart of coverage.py though, partly because of the requirement on the toml library. I have another idea: this can be a separate package, implementing a configurer plugin. The change I'd need to make in coverage.py is to find plugins via entry points rather than just explicit configuration. What would you think? |
As you suggested in #664, I made it so that toml files aren't loaded if As a user of coverage, I think I'd prefer to add e.g. |
I see your point about the convenience, and an extras would work. I appreciate the adapter class you've made here so that the toml file can be read like an ini, and I definitely appreciate you following the conventions in the rest of the code (backwards.py etc). I've haven't looked into toml, but I'm wondering if there's a simpler way to get configuration from a toml file. The adapter class seems a bit bulky for the conceptual problem to be solved? |
So the To use something else we'd need an alternate path to reading and checking types from |
@RazerM OK, I'm warming to the idea of this. I would put the How does that sound? |
BTW, I just refactored the environment variable substitution.... |
318375b
to
e770616
Compare
I should be able to write tests sometime within the next week. |
I'd very interested in helping getting this over the line- getting people to adopt pyproject.toml is really hard when a ubiquitous library like coverage doesn't support it yet :) @RazerM if your time is scarce at the moment I could help with writing tests? |
@ptink Help would be great! I think we can copy |
FYI @ptink I have started writing some tests. @nedbat one problem I've come across is environment variable substitution for non-strings (i.e. integers and booleans): [tool.coverage.run]
branch = "$OKAY" Currently, I have def getboolean(self, section, option):
value = self.get(section, option)
if not isinstance(value, bool):
raise ValueError(
'Option {!r} in section {!r} is not a boolean: {!r}'
.format(option, section, value))
return value So the options are:
Option 2 is the most user friendly, but it means users can use |
Maybe I'm missing a detail. Why would coercing a string to the type mean that "yes" would be true? Because it's a non-empty string, and "no" would also be true? That would be the strange case. I'm not sure what value you had for $OKAY that you wanted to support? Would |
Maybe coerce was the wrong word. I'll try explain what I meant. As it stands, With TOML, by the time our class gets a value, it's already whatever type was in the TOML file: >>> import toml
>>> toml.loads("""
... [run]
... branch = true
... """)
{'run': {'branch': True}}
>>> toml.loads("""
... [run]
... branch = "false"
... """)
{'run': {'branch': 'false'}} As it stands in this PR, the |
Hey folks! Is there anything I can do to help this change along? I've been investing some time trying to unify to one of |
Executable `setup.py` configuration has generally fallen out of favor, with declarative project configuration files like `setup.cfg` and `pyproject.toml` becoming more popular. The following files are subsumed by this change: * `.coveragerc` * `MANIFEST.in` * `apiron/VERSION` (thanks in part to `importlib_metadata`!) * `pytest.ini` * `requirements.txt` * `tox.ini` It also reduces `setup.py` to its minimal form. I think I would've preferred to cut over to `pyproject.toml` if we could, but [coverage does not yet support it](nedbat/coveragepy#699). This also means the configuration for `black` still sits in `pyproject.toml`, because _it_ doesn't support `setup.cfg`. Fortunately, the content of `setup.cfg` should be relatively portable to `pyproject.toml` when the time comes.
* Unify package metadata and tool configuration Executable `setup.py` configuration has generally fallen out of favor, with declarative project configuration files like `setup.cfg` and `pyproject.toml` becoming more popular. The following files are subsumed by this change: * `.coveragerc` * `MANIFEST.in` * `apiron/VERSION` (thanks in part to `importlib_metadata`!) * `pytest.ini` * `requirements.txt` * `tox.ini` It also reduces `setup.py` to its minimal form. I think I would've preferred to cut over to `pyproject.toml` if we could, but [coverage does not yet support it](nedbat/coveragepy#699). This also means the configuration for `black` still sits in `pyproject.toml`, because _it_ doesn't support `setup.cfg`. Fortunately, the content of `setup.cfg` should be relatively portable to `pyproject.toml` when the time comes. * Remove extra blank line * Revert change to install black and pyflakes only where supported * Add CHANGELOG line about setup.cfg
@daneah Do you have an opinion about the environment variable concern? I suppose the simplest thing for now would be to not support environment substitutions in pyproject.toml files, at least for non-string values. |
coverage/env.py
Outdated
TOML_SUPPORT = False | ||
else: | ||
del toml | ||
TOML_SUPPORT = True |
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.
I think this clause would be better in backward.py. I'd prefer something like:
try:
import toml
except ImportError:
toml = None
and then later using "if toml:" to check for toml support.
@nedbat I haven't used environment variable substitution in the past, and I'm not sure I was even aware it was supported until I read this conversation! That probably means I'm not a good one to provide an opinion, but maybe the data point is helpful. It does seem like the kind of thing that could be iterated on and enhanced in the future if TOML support for environment variables starts out with only strings. |
I'll resume the work on this without environment variable support for non-string values. |
Codecov Report
@@ Coverage Diff @@
## master #699 +/- ##
=========================================
- Coverage 92.23% 82.44% -9.8%
=========================================
Files 85 86 +1
Lines 11335 11529 +194
Branches 1148 1179 +31
=========================================
- Hits 10455 9505 -950
- Misses 739 1837 +1098
- Partials 141 187 +46
Continue to review full report at Codecov.
|
188bdbc
to
c24d4e6
Compare
@nedbat I think this is ready for review. If there should be more in the testing or documentation department let me know. One possible UX problem right now is if the user passes We could have a similar problem if users add configuration to their |
Tests are failing on Travis and AppVeyor. Do they pass for you locally? |
@nedbat I must have broke something when I rebased, I’ll have a look after work. |
c24d4e6
to
e54acb9
Compare
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.
Thanks for persisting with this. We are very close to being done. I can squash and merge as is, and make a few changes myself, unless you want to take care of them.
|
||
|
||
class TomlConfigParser: | ||
def __init__(self, our_file): |
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.
We don't have a case where our_file is True, so we could remove a little bit of code here.
I'm curious about the "coverage.toml" case. Is that something we need to support at all? I thought TOML support was so that we could piggyback on pyproject.toml? I guess a few of my comments would go the other way if you felt it was important to allow for "coverage.toml". |
@nedbat It supports My motivation for the PR was to be able to use TOML since I prefer the syntax. So for me, the standard One example is a new developer being able to see which values are lists at first glance: [tool.coverage.run]
source = ["mypackage"] vs
|
@RazerM What's left to do here? Issues raised so far:
I think we're OK with merging without changing them. Some things I can do after merging:
|
Oops, and docstrings :) |
I tried the crazy idea of substituting environment variables on the whole file contents at once, and the tests all pass, so maybe it's not so crazy?
|
Also, all the errors we raise in tomlconfig.py should derive from CoverageException, so that users don't get tracebacks if the error is reported on the command line. |
@RazerM previously proposed this:
So, if coveragepy finds no default configuration file except pyproject.toml, but toml is not installed, print a message. But I think it would trigger a false positive for users who have no coverage configuration but still a pyproject.toml and no toml package installed. The message should only be printed if there is coverage configuration in pyproject.toml, meaning... we must read pyproject.toml to know if we should read pyproject.toml hahaha... |
For others who have reacted on this issue: Would you use TOML support for a dedicated coverage configuration file (coverage.toml), or are you interested in this just for writing coverage configuration into a larger file like pyproject.toml? React with thumbs-up 👍 for dedicated coverage.toml file. /cc @pawamoy @daneah @tpansino @DolanMaize @ptink @ipmb @sweenu |
@pawamoy For the "no TOML installed" warning, riffing on the "read the whole TOML file as a string" idea, we could just search that string for "[tool.coverage." and warn if it's found. |
Supporting separate |
I voted with a thumbs down (only larger toml file) because I'm only interested in putting my config in pyproject.toml. However I'm absolutely not against having the option to specify another TOML file to read the config from. If I understand correctly, nobody asks coveragepy to support a dedicated
To summarize: I'm only interested in pyproject.toml, though others (and maybe myself later) find the ability to do |
Coming soon! Issue: nedbat/coveragepy#664 PR: nedbat/coveragepy#699
@RazerM I'm going to clean this up and merge it, thanks! |
Squashed and rebased from #699 Missing getfloat TOMLConfigParser -> TomlConfigParser fix getfloat for int Move TomlConfigParser Add name to contributors Import toml in backward.py fix indentation Don't ignore TomlDecodeError Raise if TomlConfigParser is used without toml installed Add tests for TOML config Fix test on Python 2 Mention toml support in documentation.
Squashed and rebased from #699 Missing getfloat TOMLConfigParser -> TomlConfigParser fix getfloat for int Move TomlConfigParser Add name to contributors Import toml in backward.py fix indentation Don't ignore TomlDecodeError Raise if TomlConfigParser is used without toml installed Add tests for TOML config Fix test on Python 2 Mention toml support in documentation.
Missing docstrings and tests at the moment. If this looks like the right idea I can start adding those.
Example
pyproject.toml
:Resolves #664