-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Add OuputVerbosity and use it in assertions #11473
Conversation
src/_pytest/config/__init__.py
Outdated
return f"verbosity_{output_type}" | ||
|
||
@staticmethod | ||
def add_ini(parser: "Parser", output_type: str, help: str) -> None: |
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.
Since many things will add these type of settings, I thought it would be helpful to have this function to ensure it is dong consistently. I'm not completely in love with this level of indirection. But it is necessary since config settings are added to the Parser
before the Config
object exists.
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.
Good idea. 👍
class Config: | ||
def getoption(self, name): | ||
if name == "verbose": | ||
def mock_config(verbose: int = 0, assertion_override: Optional[int] = None): |
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.
With the move away from getoption()
, this needed to get a bit more complicated. (In the long term, it would probably be beneficial move the code base to a consistent way to access the verbosity level.)
Since this is my first contribution, I'm not sure the best way to get a review for this PR that has been up for 3 weeks. @nicoddemus & @Zac-HD, you both interacted with the issue. Would one of you be able to review this code? |
Sorry @plannigan, you are not supposed to do anything else other than opening the PR: we dropped the ball for not reviewing it earlier (I personally have been busy). When that happens a ping (like you did) is appreciated, thank you! I will try my best to review this in the next couple of days. 👍 |
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.
Great work @plannigan, and sorry again for the delay!
The implementation is good, however I think we might need some more interactions given this introduce a new API, which must be done carefully and with care.
src/_pytest/config/__init__.py
Outdated
return f"verbosity_{output_type}" | ||
|
||
@staticmethod | ||
def add_ini(parser: "Parser", output_type: str, help: str) -> None: |
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.
Good idea. 👍
src/_pytest/config/__init__.py
Outdated
"""Application wide verbosity level.""" | ||
return cast(int, self._config.option.verbose) | ||
|
||
def verbosity_for(self, output_type: str) -> int: |
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 if one passes an invalid output_type
at the moment, we will get an error (due to self._config.getini
).
We probably want to have this classs accessible to plugins and users, via config.output_verbosity
, so we need to think about its API carefully as we will need to support this officially moving on.
Some points:
-
In tandem with pytest's direction regarding type safety, I think we should use an
Enum
with the output types currently available, something along the lines of:class VerbosityType(Enum): """...""" Global = "global" Assertions = "assertions"
Instead of a simple
output_type: str
parameter/value. -
The class name is
OutputVerbosity
and the public methods areverbosity
andverbosity_for
, which read a bit redundant:confg.output_verbosity.verbosity
,confg.output_verbosity.get_verbosity_for
. I suggest we use simplyget
, defaulting to theGlobal
verbosity:def get(self, type: VerbosityType = VerbosityType.Global) -> int: ...
Which reads well I think:
config.output_verbosity.get() config.output_verbosity.get(VerbosityType.Assertions)
-
We need to properly document both
OutputVerbosity
andVerbosityType
in the reference docs (including some usage examples, but possibly we can write those in the class docstring). We also need to exposeVerbosityType
in thepytest
namespace. -
Given
OutputVerbosity
is public, we should makeOutputVerbosity.addini
private, as it is intended for internal use only.
I'm not married to the names above, so suggestions and bikeshedding are welcome.
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 opted for
str
because I was thinking that plugins might want also register types, like any other config setting. Which would mean that it wouldn't be possible to statically define all of the types. However, reflecting on that, I'm not sure that level of extensibility is necessary. It is likely better forpytest
to say "here are N buckets that a plugin can utilize" and that way users of multiple plugins that leverage this functionality will see consistent behavior without needing to enable M settings. - That is fair. It also works nicely with the enum suggestion.
- Sure
- I had it as public for the reasons described in 1, but it makes sense to make it private based on that change.
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'm not able to do a full review ATM, but left some quick comments.
Fine gain verbosity | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
In addition to specifying the application wide verbosity level, it is possible to control specific aspects independently. |
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.
Since we only have one aspect at the moment, it seems premature to write the prose in a general/list format.
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.
My intention is to implement some of the other verbosity types I identified once this PR is merged. A different suggestion was to add a note that only one is currently supported. That seems sufficient to me if "life happens" and it takes me some time to get to adding other types.
src/_pytest/config/__init__.py
Outdated
@@ -1662,6 +1663,54 @@ def _warn_about_skipped_plugins(self) -> None: | |||
) | |||
|
|||
|
|||
class OutputVerbosity: |
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.
Why OutputVerbosity
and not just Verbosity
? I can't think of a verbosity that is not related to output, so it seems redundant.
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'm open tweaking the name. I generally default to more explicit names.
Co-authored-by: Ran Benita <[email protected]> Co-authored-by: Bruno Oliveira <[email protected]>
* Use enum instead of string * Change method name to simple get * Make type registering internal
I believe I have addressed the technical comments and documentation requests. I'm not sure why the doc building step is failing. The error don't seem to be related to the lines I changed. If someone with more experience with |
The problem was that you used |
3f2b440
to
b8714de
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 the update @plannigan, my comments:
-
The
OutputVerbosity
andVerbosityType
seem more complicated than necessary to me. What is the advantage over doing it the direct way, i.e. adding the ini directly and maybe adding a getter onConfig
? -
If we stick with
OutputVerbosity
, let's make it justVerbosity
-- theOutput
part is entirely redundant IMO. -
We should have at least one end-to-end test (
pytester.runpytest
test) which shows this working, i.e. changing the output vs. not setting the ini.
I think this is to handle the fallback to default verbosity when the setting is defined in the ini file.
Can you clarify what you mean here, do you mean adding:
|
Yes, any of these would be fine by me. |
One nice effect of implementing some functionality directly in Using Suppose in the future we add if hasattr(config, "output_verbosity") and hasattr(pytest, "VerbosityType") and hasattr(pytest.VerbosityType, "Rubles"):
rubles_verbosity = config.output_verbosity.get(pytest.VerbosityType, Rubles)
else:
rubles_verbosity = config.option.verbose While using option 2) above users can go with: if hasattr(config, "get_verbosity"):
rubles_verbosity = config.get_verbosity("rubles")
else:
rubles_verbosity = config.option.verbose |
Looks like one of the jobs failed with a file system error in an area I didn't touch. I don't have permissions to retry the job. |
Started it again. 👍 |
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.
Haven't had time for a full review again, but left some comments, please take a look.
src/_pytest/config/__init__.py
Outdated
return f"verbosity_{verbosity_type}" | ||
|
||
@staticmethod | ||
def _add_ini(parser: "Parser", verbosity_type: str, help: str) -> None: |
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.
Same here, the name _add_ini
is too general now.
Also, IMO this function doesn't add much value, I think it would be better to reduce the indirection and inline it. But since it's private then it's OK if you want to keep it.
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 prefer to keep it because it will avoid duplication as more types are added. It also ensures that the same default is used across verbosity types. If someone adds an Nth type, but uses "global", then get_verbosity()
will raise an exception.
* don't use implementaiton for setting name * str() of path object is not needed
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 the update @plannigan, please see my comment on _KNOWN_VERBOSITY_TYPES
. Other than that it looks good!
src/_pytest/config/__init__.py
Outdated
assert isinstance(global_level, int) | ||
if ( | ||
verbosity_type is None | ||
or verbosity_type not in Config._KNOWN_VERBOSITY_TYPES |
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 it would be better to avoid this check, so that plugins can add their own verbosity types. We would instead check if the ini exists.
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 like the idea of checking the ini data instead (one less thing to manually manage).
In a previous conversation, there was a conversation about plugins creating their own levels. I think I'm still in the "pytest can enumerate a few buckets" camp. @nicoddemus Do you have any thoughts? If we did allow plugins to create types, _add_verbosity_ini
would have to be made public and some more documentation updates.
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 we can keep it simple for now, making this internal only; if the need comes later, we can discuss how to make this public -- better to err on the side of caution, as it is easy to make something public later, rather than making something public and then regretting it 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.
LGTM! I know this feature will make a lot of people happy :)
I'll let @nicoddemus do the final review/merge.
Thanks everyone! |
OuputVerbosity
is a new class that allows for retrieving a verbosity level for a specific output type. If nothing is specifically configured, the application wide verbose value is used.The first use of this functionality is
verbosity_assertions
which can be used to make the assertion reports output at the most verbose level while still showing a single character for each test case when progress is being reported.Addresses #11387