-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
MNT/TST: generalize check_figures_equal to work with pytest.marks #15199
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
MNT/TST: generalize check_figures_equal to work with pytest.marks #15199
Conversation
Generalize (at the cost of reaching a little bit into pytest internals) the check_figures_equal decorator so it works as expected with `pytest.mark.paramatarize`
lib/matplotlib/testing/decorators.py
Outdated
|
||
wrapper.pytestmark = get_unpacked_marks( | ||
wrapper | ||
) + get_unpacked_marks(func) |
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 not something you can add together from wrapper.pytestmark
and func.pytestmark
?
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 that actually part of the public API?
Internally, pytest uses these three functions to do the mark manipulation:
def get_unpacked_marks(obj):
"""
obtain the unpacked marks that are stored on an object
"""
mark_list = getattr(obj, "pytestmark", [])
if not isinstance(mark_list, list):
mark_list = [mark_list]
return normalize_mark_list(mark_list)
def normalize_mark_list(mark_list):
"""
normalizes marker decorating helpers to mark objects
:type mark_list: List[Union[Mark, Markdecorator]]
:rtype: List[Mark]
"""
extracted = [
getattr(mark, "mark", mark) for mark in mark_list
] # unpack MarkDecorator
for mark in extracted:
if not isinstance(mark, Mark):
raise TypeError("got {!r} instead of Mark".format(mark))
return [x for x in extracted if isinstance(x, Mark)]
def store_mark(obj, mark):
"""store a Mark on an object
this is used to implement the Mark declarations/decorators correctly
"""
assert isinstance(mark, Mark), mark
# always reassign name to avoid updating pytestmark
# in a reference that was only borrowed
obj.pytestmark = get_unpacked_marks(obj) + [mark]
I was between just vendoring them all, doing the semi-private import, or adding the obj.pytestmark
list together. I took the middle route, I'll change it to just adding the pytestmark
lists together.
lib/matplotlib/testing/decorators.py
Outdated
sig = inspect.signature(func) | ||
new_sig = sig.replace( | ||
parameters=( | ||
[ |
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.
As a side note, I find your code formatting style extremely hard to read.
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 this just looks like the worst of black
, things like
wrapper.pytestmark = get_unpacked_marks(
wrapper
) + get_unpacked_marks(func)
just completely obfuscate the structure of the code -- compare with
wrapper.pytestmark = (get_unpacked_marks(wrapper)
+ get_unpacked_marks(func))
(or with an additional newline after the opening parenthesis).
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 indeed black's doing.
Ironically, the biggest selling point of black for me is avoiding exactly these conversations.
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.
The fact that it's automated doesn't absolve it from completely violating basic esthetics.
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.
fwiw @NelleV and I have been trying to come up with a better automated scheme and it's certainly not trivial... Nevertheless, since afaict matplotlib hasn't added black as a dependency, it's a bit weird to add badly black-formatted code...
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 @tacaswell it looks like you've set it to 71c wide? Which is unconventional to say the least...)
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 personally just don't buy into the idea that code can be properly formatted without understanding the underlying semantics.)
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.
(Juan is considering doing constrained reinforcement learning to learn the rules…)
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 thought I set it to 80c (to keep our pyflakes happy). Black does a slightly better job if you give it a bit more width to work with.
I'm having a hard time understanding whether this is worth it. There's a chance this gets broken without warning between two pytests version. |
I compressed the code a bit. I'm not convinced it is actually more readable..... |
@meeseeksdev backport to v3.2.x |
… to work with pytest.marks
…199-on-v3.2.x Backport PR #15199 on branch v3.2.x (MNT/TST: generalize check_figures_equal to work with pytest.marks)
PR Summary
Generalize (at the cost of reaching a little bit into pytest
internals) the check_figures_equal decorator so it works as
expected with
pytest.mark.paramatarize
PR Checklist