-
-
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 log-auto-indent option to control multiline formatting #5926
Conversation
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.
@earthman1 thanks a lot, overall a great and well written PR!
Please take a look at my comments and let us know your thoughts. 👍
src/_pytest/logging.py
Outdated
@staticmethod | ||
def _update_message(record_dict, message): | ||
tmp = record_dict.copy() | ||
tmp["message"] = message | ||
return tmp | ||
|
||
def _get_auto_indent(self, record): |
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.
Can we add a docstring here please? It is not entirely obvious all that's being done here.
I also suggest turning this into a function:
def get_auto_indent(record, default_auto_indent) -> int:
Where default_auto_indent
is self._auto_indent
at the call site.
Then we can unittest this function in isolation and account for all the branches and cases it handles. 👍
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.
Docstring: yes, I'll create that now.
Altering the method definition: Yes, I can make that static. Do you feel it is important to make the method public? To me it feels like it is private, but I don't know your views on calling private methods from the unittests.
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 respect to the docstring, you indicated that the purpose for it is that "It is not entirely obvious all that's being done here." As I began to write it, it started to seem wordy, because I'm trying to address your concern. Do you really want something detailed?
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.
More about the overall purpose of the method
Altering the method definition:
I meant to make it a function; the fact that it is public is not really relevant, because the module itself is not public (but it is OK to import the private module on our own test suite).
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 changed this to a static method as requested, but I also added new test cases to get the code coverage up to 100% so the use case for making the method public seems less urgent now
src/_pytest/logging.py
Outdated
"--log-auto-indent", | ||
dest="log_auto_indent", | ||
default=None, | ||
help="auto indent multiline messages passed to the logging module. accepts true|on, false|off or an integer", |
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 sure we need to support on/off
... any reason for 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.
To confirm, you mean only support true/false and remove support for on/off?
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.
No specific need to support on/off. If you'd like me to remove it, let me know.
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.
To confirm, you mean only support true/false and remove support for on/off?
Exactly, sorry I wasn't clear. Let's remove it, no need to have support for two set of options. 👍
Thanks!
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 ended up taking a different route with respect to this discussion. I discovered that there is a strtobool
method in pytest's config module, which I simply imported and reused for this purpose, which means I don't need to hard-code the accepted values for the strings, and it will simply accept the same strings as all the config options.
It also happens to be that the standard for all pytest config options is to accept y/n, yes/no, t/f, true/false, on/off and 1/0, so now this option will follow that standard as well.
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, good call
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.
Thx for working on this @earthman1 !
changelog/5515.feature.rst
Outdated
``[value]`` can be: | ||
* True or On - Dynamically auto-indent multiline log messages | ||
* False or Off or 0 - Do not auto-indent multiline log messages | ||
* [integer] - auto-indent multiline log messages by [integer] spaces |
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 that you've added support for configuring the the indentation level explicitly!
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
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.
s/integer/positive integer/ ?
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'd rather see a link from the changelog to docs, instead of having it expanded/explained that much there.
(people apparently (according to #5952 at least) will find it then in the changelog, and might see an out-of-date documenation)
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.
s/integer/positive integer/ ?
Agreed
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'd rather see a link from the changelog to docs, instead of having it expanded/explained that much there.
Can you provide more detail what you'd like to see here, or perhaps the exact text you prefer? I'm not sure what you're looking for.
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.
@earthman1
Not sure what's unclear.. the changelog basically documents the feature/change, while that should be in the docs themselves instead (where it gets updated in the future).
I.e. https://github.com/pytest-dev/pytest/blob/817a42d48fb00cf50553facecdbbc24dadabf36c/changelog/5515.feature.rst should go into https://github.com/pytest-dev/pytest/blame/914a9465aba501e776282961fb3317837772435d/doc/en/reference.rst#L1196, and then the changelog should link to that (IIRC that's not possible though due to pre-commit failing on it then.. #4283). So assuming #4283 is still a problem, it should just mention/describe the setting briefly, but not document it there.
changelog/5515.feature.rst
Outdated
and config option ``log_auto_indent`` to set the default for all logging. | ||
|
||
Supports passing kwarg ``extra={"auto_indent": [value]}`` to | ||
calls to ``log.log()`` to specify auto-indentation behavior for |
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.
What do you mean by log.log
? Probably you mean logging.log from the stdlib, right? Please try to make this a bit clearer in the changelog entry.
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.
You're right, of course. I'll change that
changelog/5515.feature.rst
Outdated
Supports command line option ``--log-auto-indent [value]`` | ||
and config option ``log_auto_indent`` to set the default for all logging. | ||
|
||
Supports passing kwarg ``extra={"auto_indent": [value]}`` to |
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.
What is the motiviation for adding an auto_indent parameter to log.log
? Do you want to configure auto_indent per log record?
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.
yes, this adds per log line support, so that you can strategically turn it off when printing a preformatted table of trace info, for example.
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.
@earonesty is correct. Sometimes it is good to leave it default on, and then strategically turn it off on a particularly long log entry that doesn't want to be pushed so far to the right, or to set the indentation position to a position that is suited to that entry
src/_pytest/logging.py
Outdated
specified. | ||
|
||
Any other values for the option are invalid, and will silently be | ||
converted to "on". |
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.
Please document the meaning of the return value using the :returns:
directive
sth like
:returns: indenation value, which can be
-1 (automatically determine indentation) or
0 (auto-indent turned off) or
>0 (explicitly set indentation position).
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.
Will add that
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.
Thx!
add_option_ini( | ||
"--log-auto-indent", | ||
dest="log_auto_indent", | ||
default=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.
Why do you set auto-indent by default to None and not to "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.
My preference is to set the variables that represent options to None
if the option is not specified, rather than to a valid value, so that the default condition can be distinguished from the user explicitly choosing the default. This can make a difference when there are multiple ways to specify the option, and have it fall back if the option was not explicitly set.
This may not specifically relate to the setting I'm working on, but I find it to be a good practice overall because it may not be clear up front whether or not distinguishing the default from an explicit choice equal to the default may be necessary 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.
FTR I like this approach too.
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.
Thx for the explaination.
src/_pytest/logging.py
Outdated
elif default_auto_indent is not None: | ||
in_auto_indent = default_auto_indent | ||
else: | ||
in_auto_indent = -1 |
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.
This branch is only reachable if the user didn't specify a parameter to log-cli-level. Maybe we don't need distinguish between default_auto_indent being None and not-None.
src/_pytest/logging.py
Outdated
if type(in_auto_indent) is int: | ||
out_auto_indent = in_auto_indent | ||
if type(in_auto_indent) is str: | ||
if in_auto_indent.lower() == "true" or in_auto_indent.lower() == "on": | ||
out_auto_indent = -1 | ||
elif in_auto_indent.lower() == "false" or in_auto_indent.lower() == "off": | ||
out_auto_indent = 0 | ||
else: | ||
try: | ||
out_auto_indent = int(in_auto_indent) | ||
except ValueError: | ||
out_auto_indent = -1 | ||
elif type(in_auto_indent) is bool: | ||
if in_auto_indent: | ||
out_auto_indent = -1 | ||
else: | ||
out_auto_indent = 0 |
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.
Please move this code to a new method and call it in __init__
, where you assign the return value to self._auto_indent and in _get_auto_indent
. You can then change the implemenation of _get_auto_indent to
def _get_auto_indent(self, .....):
if hasattr(record, "auto_indent"):
# passed in from the "extra={}" kwarg on the call to log.log()
out_auto_indent = self.TODO_NEW_METHOD(record.auto_indent)
else:
out_auto_indent = self._auto_indent
return out_auto_indent
Since the above method is very simple you can also move it directly to def 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.
I followed this advice in the latest iteration, including calling this code for the config option in the __init__
, but I did not need to create a new method. Having moved the code to def format
as you suggested, this left all the code that would have been moved to a new method already isolated in def _get_auto_indent
, so this accomplished what I believe you had intended.
add_option_ini( | ||
"--log-auto-indent", | ||
dest="log_auto_indent", | ||
default=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.
Thx for the explaination.
src/_pytest/logging.py
Outdated
specified. | ||
|
||
Any other values for the option are invalid, and will silently be | ||
converted to "on". |
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.
Thx!
Any suggestions how to resolve the codecov/changes failing check? I don't know what "1 file has unexpected coverage changes not visible in diff" means. |
After checking, my diff has 100% code coverage, and I don't see how I might have reduced coverage elsewhere |
I rebased from the features branch and force pushed in order to fix the base that codecov was comparing against. It still does not pass codecov, so a little assistance getting this approved PR over the finish line would be greatly appreciated |
The changes to junitxml in the coverage report are due to flakiness (see #5959). You can ignore it here. |
testing/logging/test_formatter.py
Outdated
record.auto_indent = False | ||
output = ai_on_style.format(record) | ||
assert output == ( | ||
"dummypath 10 INFO Test Message line1\n" "line2" |
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.
This is hard to read / confusing.
Please consider using .splitlines()
instead and comparing lists instead.
Also below.
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.
If black gets in your way here you can also use # fmt: off
… # fmt: on
..
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.
This is the way the test was written before I introduced my feature change. I merely duplicated the check within the existing test, and adjusted it to check for the new behavior
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.
This is all new code, and I do not see "…line1\n" "line2"
being used anywhere before?!
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.
lines 58-61
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.
Personally, I agree the current behavior might not be a desirable default for some ... but I'd be wary of changing it out from under existing users. For example: if people have done curious things with their ci logs, like parsing them and loading them into splunk, changing the default would cause those same people may have to modify their parsers. I'm all for keeping the current default ... not because it's particularly more or less sane, but because leaving defaults the same is often a good choice.
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.
@earonesty
Thanks for the feedback. I've thought we only changed this recently, but it is in 4.6.0 already (c8d23c2).
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.
But according to #5312 (comment) it does not only affect the output, but also existing tests where .text
is different then..! (not sure if that is addressed here when changing the output, and/or was fixed inbetween already).
Therefore (and in general) I'd be still +1 to restore the behavior before 4.6.0 by default (i.e. change the defaults in this PR). It is unfortunate that it would change back and forth then, but seems to be better / more sane in the long term.
I assume @asottile agrees here (using pytest as a tool that should not do too much magic)?
@Thisch
What do you think?
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 agree with @blueyed here. We should restore the default behavior (before 4.6) and at some point think about moving the multiline code (and the colored log formatter as well) to a separate pytest plugin, because this would simplify the logging plugin a bit (not sure if this simplification is worth the effort, though).
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.
And as a justification of the restoration of the old default value, I would only say in the changelog that
"It is better to activate new features that may lead to broken tests explicitly instead of implicitly."
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 a lot for the great contribution @earthman1!
src/_pytest/logging.py
Outdated
"--log-auto-indent", | ||
dest="log_auto_indent", | ||
default=None, | ||
help="auto indent multiline messages passed to the logging module. accepts true|on, false|off or an integer", |
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, good call
Are there any remaining tasks with respect to the PR? |
From my side: #5926 (comment) and #5926 (comment). |
I made the change to the changelog/reference.rst |
Let me know if there are any remaining tasks for me |
Thanks for the doc/changelog update. |
Any suggestion how to proceed? |
Permit to propose a solution to the current obstacle. I will create a second PR that changes the default from true to false, and then once that PR looks good to you, you can feel better about merging this improvement, and still debate that issue, isolated to the PR that effectuates that specific change. |
Why not change it here already? |
I can change it here, but I am under the impression that changing the default is a matter of further discussion. If we permit the configurability of auto-indentation to be isolated from the changing of the default, that allows this merge to go in without waiting for the resolution of that discussion. Having a separate PR up that changes the default, that is a branch off of |
It looks like there is a consensus building around reverting the default from True to False. I anticipate to submit this change tomorrow. |
The default has been changed to log_auto_indent off. Let me know if you have any further comments, questions or requests. |
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.
Thx so much for incorporating our suggestions. I still only have some minor suggestions.
``[value]`` can be: | ||
* True or On - Dynamically auto-indent multiline log messages | ||
* False or Off or 0 - Do not auto-indent multiline log messages | ||
* [positive integer] - auto-indent multiline log messages by [value] spaces |
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.
Please mention that auto-indentation is turned off by default.
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.
done
doc/en/reference.rst
Outdated
auto-indentation behavior for all logging. | ||
|
||
``[value]`` can be: | ||
* True or On - Dynamically auto-indent multiline log messages |
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.
Maybe add quotes around On.
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.
done
doc/en/reference.rst
Outdated
|
||
``[value]`` can be: | ||
* True or On - Dynamically auto-indent multiline log messages | ||
* False or Off or 0 - Do not auto-indent multiline log messages |
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 for Off
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.
done
doc/en/reference.rst
Outdated
Some examples of using the ``extra`` kwarg might be: | ||
|
||
.. code-block:: python | ||
|
||
import logging | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
def test_multiline(): | ||
log.debug("line 1\nline 2 indented", extra={"auto_indent": True}) | ||
log.warning("line 1\nline 2 not indented", extra={"auto_indent": "off"}) | ||
log.log( | ||
logging.ERROR, "line 1\nline 2 indented by 5 spaces", extra={"auto_indent": 5} | ||
) |
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 sure if we need an usage example for the extra
kwarg. I think the paragraph starting at L1213 explains the feature pretty well and doesn't need an additional code block.
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.
done
As before, please let me know if there are any remaining tasks or questions. Thx |
changelog/5515.feature.rst
Outdated
Alters the default for auto-indention from ``on`` to ``off``, | ||
reverting to the behavior prior to v4.6.0. This reversion to earlier | ||
behavior was done because it is better to activate new features that | ||
may lead to broken tests explicitly rather than implicitly. |
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.
Sorry to be annoying, but I think the changelog should clearly mention that this restores the (older) behavior.
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.
Can you provide the language you need? I felt that "...reverting to the behavior prior to v4.6.0. This reversion to earlier behavior was done because..." did clearly indicate that we are restoring old behavior.
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.
Sorry to be annoying, but I think the changelog should clearly mention that this restores the (older) behavior.
You're not annoying, you're committed to quality.
I changed the wording of the changelog to be closer to the wording in your request. Please let me know if I can improve this further, or if there are any other requests you may have.
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, thanks!
Delegating to @Thisch (reviewed again already) @nicoddemus (please check if you still like it).
Just pointing out and cementing the fact that at 100 mentions, this is the most commented pull req of all 2000+ reqs in this repo's history. |
@nicoddemus I would like to merge this PR. Any objections/suggestions? |
Wow, I hadn't noticed that. Funny link: PRs sorted by most commented I think it's more like 2,600 or so PRs at this point. The original PR had 8 comments :-) |
Haven't seen any activity on the PR in a week, just checking in |
Yeah... Since @Thisch approved a week ago already, and I am very happy for you to have understood my commitment to quality I'm going to merge it now. Thanks a lot! (also to everyone having contributed to the constructive part of the 100+ comments) |
Allow selective auto-indentation of multiline log messages.
Supports command line option
--log-auto-indent [value]
and config option
log_auto_indent
to set the default for all logging.Supports passing kwarg
extra={"auto_indent": [value]}
tocalls to
log.log()
to specify auto-indentation behavior fora specific entry in the log.
[value]
can be:* True or On - Dynamically auto-indent multiline log messages
* False or Off or 0 - Do not auto-indent multiline log messages
* [integer] - auto-indent multiline log messages by [integer] spaces
extra
kwarg overrides the value specified on the command line or in the config.Implements feature request #5515