-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Deprecation of msg= for both pytest.skip() and pytest.fail().
#8950
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
Deprecation of msg= for both pytest.skip() and pytest.fail().
#8950
Conversation
|
@The-Compiler @RonnyPfannschmidt @nicoddemus opened a draft here, I am unsure the best approach for something like this so I welcome any feed back, I have ran out of time this evening so I thought I would try get a conversation started around it for me to pick up later and tweak, few queries:
|
RonnyPfannschmidt
left a comment
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 start 👍 , please address the minor nitpicks
|
I have excluded |
nicoddemus
left a comment
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.
@symonk thanks for the PR, great work!
I left some minor comments, please take a look.
Also, it is important to add a section to doc/en/deprecations.rst mentioning the deprecation, rationale, and how to update existing code. After doing that, add a link to the new section to the changelog/8948.deprecation.rst file.
pytest.skip(msg=...) in favour of pytest.skip(reason=...)msg= for both pytest.skip() and pytest.fail().
As always, thanks again! appreciate it. |
nicoddemus
left a comment
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.
Looks great, thanks! Left two minor changes, otherwise LGTM!
Co-authored-by: Bruno Oliveira <[email protected]>
Co-authored-by: Bruno Oliveira <[email protected]>
|
pre-commit.ci run |
|
thoughts on getting this in for |
|
I'm fine with getting this for 7.0. 👍 |
|
Fine by me, given that 7.0 is delayed a bit more anyways (I intend to pick it up again in 2-3 weeks after I've had some holidays) |
|
please ignore spending any time looking at this until I sort it out, as soon as possible :) I'm going to implement deprecation as a decorator to handle all 3 cases, |
Cool, thanks! Also reminder to then mention |
will do, got it done locally just need to test my changes but I've had no time the past 2 days, hopefully do it tonight because i'm away this weekend :) |
|
@nicoddemus any advice on how best to handle the exit() case, by default it is alternatively, all I can think of is something like a decorator like: def deprecate_msg_for_reason(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
if "msg" in kwargs:
kwargs["reason"] = kwargs["msg"]
del kwargs["msg"]
warnings.warn(KEYWORD_MSG_ARG.format(func=f.__name__), stacklevel=2)
return f(*args, **kwargs)
return wrapperCurious on some feed back before i spend time implementing it, the problem with the decorator approach is it leaves a lackluster sig where an arg is probably defined but unused, or like:
which feels bad to me, in the decorator approach neither are used in the function scope |
|
Hey @symonk
I think so, any reason you feel this should be handled differently? |
|
Thanks @nicoddemus I wasen't sure if there was a reason why edit: That makes my life a little easier! I was cautious of changing as I assumed there was a reason behind why it was non optional |
|
Ahh I see! Sorry, now I get why you asked. But we need to have a message associated with it, otherwise we don't have a reason to show. How about this? def exit(reason: str="", *, msg: Optional[str]=None):
if reason and msg:
raise UsageError("Cannot pass both reason and msg to exit")
if not reason:
if msg is None:
raise UsageError("exit() needs a reason argument")
warnings.warn("msg is deprecated, use reason instead")
reason = msg
# use `reason`We can then explain in the docstring that |
I like it, i will keep the reuse for |
|
out of time tonight, need to look into a few linting oddities in: ailing in CI too, kinda puzzled as i haven't touch that file, i did change fail() tho ofc, maybe to do with that, will chase that up later and tidy up a few loose ends, will prompt for review when I finish up, thanks again. mini task list for later:
|
src/_pytest/outcomes.py
Outdated
| if msg is not None: | ||
|
|
||
| if reason: | ||
| fail( |
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.
is this technically correct for the skip scenario? not sure.
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 call fail you mean?
Hmmm you probably should not call fail, but raise UsageError.
|
What's the state of this? I plan to get back to a 7.0 rc1 soon (possibly next week), and if this doesn't make it into the RC, I don't think we should have it in the 7.0 final either. |
|
@The-Compiler I will set aside some time tomorrow morning and finish this off, I have some family stuff on after work this evening, hopefully it will be wrapped up by midday or so tomorrow. edit: more than expected to sort when bringing |
src/_pytest/scope.py
Outdated
| ) | ||
| # I don't know why mypy complains here, `fail()` is typed as `typing.NoReturn` | ||
| # yet it complains of error: Missing return statement [return] ? | ||
| assert False, "unreachable" |
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.
Anyone savvy with mypy knows why it complains of a missing return here? the Scope instantiation is correctly catching the ValueError and fail() has a forward ref return type of "No Return". This seems unnecessary? to me
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.
cc @bluetech
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.
Looks like a mypy bug or at least something mypy can improve. Maybe the "missing return value" analysis does not consider unreachability (which is correctly detected in this case, I verified this by adding some statement after the fail and seeing that mypy complains that the statement is unreachable).
If you want to avoid the assert you can replace return ... with scope = ... and return scope outside of the try-except. Slightly less clean but OK I 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.
Whatever you folks think is best I will happily implement, kind of a rock and a hard place here :)
- keep assert as is
- hold a reference
scopeand return it after the except
(may have some issues around local variables referenced before assignment that won't break anything in the latter)
In the mean time I will try recreate and open a mypy issue (if one is required)
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 go with "hold a reference scope and return it after the except".
Reported to mypy would be nice, if you are able to reduce it to a standalone example. You should check if it has already been reported 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.
@bluetech Will do! thanks
|
Moved to a |
nicoddemus
left a comment
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 a lot @symonk!
|
@nicoddemus @RonnyPfannschmidt @The-Compiler @bluetech - Thanks as always for all the feed back here, I think it is good to go (I've applied Rans latest suggestion), would be good to wrap this up for |
The-Compiler
left a comment
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.
Phew, this turned out quite a bit more complex than I had imagined! Great work @symonk, thanks for the determination! 👍
|
@RonnyPfannschmidt I think your review comments have all been addressed, correct? |
|
Indeed |
|
Let's get this in then, thanks everyone! |
Hi all, hope you are well :) I have an initially poc at refactoring the
pytest.skip(msg=...)syntax in favour of areason=arg in the sig, I have attempted to deprecate this for now in the simplest way I can think possible. I have ran out of time tonight so opened this PR for a discussion in the interim.I am not familiar with how we deprecate things in general here in pytest, especially not function signature args. Please let me know what you think, if i'm on the right track etc.
We have a few circular imports I need to spend more time on, we should maybe also consider
OutcomeExceptionusing areasonattr itself, however I'm aware there are other use cases that currently usemsg=.closes #8948
This needs a lot of work, opening it as a draft