-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Single-line string notation for subplot_mosaic #18763
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
4c48f7e
to
469cfbe
Compare
469cfbe
to
235165b
Compare
@@ -1776,8 +1776,13 @@ def get_tightbbox(self, renderer, bbox_extra_artists=None): | |||
|
|||
@staticmethod | |||
def _normalize_grid_string(layout): | |||
layout = inspect.cleandoc(layout) | |||
return [list(ln) for ln in layout.strip('\n').split('\n')] | |||
if '\n' not in layout: |
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 not do if ';' in layout? Should ';\nA' be valid?
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've designed this PR to not change the behavior of multi-line strings. I've just added the possibility of single-line strings. Therefore the check is between those two options ("Do I have a line break?").
Whether or not we want stronger checking for the multi-line case is orthogonal.
@@ -758,6 +758,24 @@ def test_subplot_kw(self, fig_test, fig_ref, subplot_kw): | |||
|
|||
axB = fig_ref.add_subplot(gs[0, 1], **subplot_kw) | |||
|
|||
def test_string_parser(self): | |||
normalize = Figure._normalize_grid_string |
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.
Should possibly be paramterized instead of reassigning the function name if the point of the reassignment is to not have to write the long name (& also these tests are really testing different conditions)
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 you strictly go by the book, yes all these assertions could be separate tests and thus be parametrized. However, from a practical point of view, an explicit assert normalize('ABC') == [['A', 'B', 'C']]
is much more readable than
@pytest.mark.parametrize('str_layout, list_layout', [
('ABC', [['A', 'B', 'C']]),
...
])
test_string_parser(str_layout, list_layout):
assert Figure._normalize_grid_string(str_layout) == list_layout
And for readability, I'll accept shortening the function name and doing all assertions in one test. IMHO that's still better.
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 test output readability is better though? (I don't know what the output looks like here.
Also my concern isn't readability so much as there's no way to see that multiple conditions fail since by definition the first failed assert will fail the test.
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 the test passes there is no output. In case of failure, you get a traceback including a printout of the failed assert statement. IMHO the assert is a bit more readable with the explicit strings, compared to using variables and resolving them ("... where str_layout = ... and list_layout = ...").
But actually I'm more concerned with the readability of the test. The tests are validated examples. They define the API we actually guarantee (docstrings can claim anything). Thus, they are a source of information and should be easily readable.
You are right with the multiple conditions. It's very well possible that multiple assertions fail if someone messes up the parser. However, I believe that knowing multiple asserts failed does not help for debugging in this context. Pytest will tell you the number of broken tests. If there is one, you go there and immediately see "My change broke the mosaic parser". If you have 3 failed tests, you have to check all three to see that you only broke the parser but nothing else. This is significantly more cumbersome. IMHO the added information "My change broke the mosaic parser in three ways" does not help much. In practice, you will anyway go to the first failed test and try to make that work 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.
I agree with @timhoffm this is is more readable an informative than what it would look like with @pytest.mark.parameterize
and that splitting this out into N tests would not provide much benefit.
@@ -758,6 +758,24 @@ def test_subplot_kw(self, fig_test, fig_ref, subplot_kw): | |||
|
|||
axB = fig_ref.add_subplot(gs[0, 1], **subplot_kw) | |||
|
|||
def test_string_parser(self): | |||
normalize = Figure._normalize_grid_string |
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 test output readability is better though? (I don't know what the output looks like here.
Also my concern isn't readability so much as there's no way to see that multiple conditions fail since by definition the first failed assert will fail the test.
I just tried to use this and am sad it is not there. |
Ping @story645 #18763 (comment) please comment. |
I continue to disagree w/ you and @tacaswell about the tests - having an overview of the different ways in which you broke something can lead to a faster solution than only learning about the different ways you broke something as you unbreak it. And here as the parameterization is two values, I think it's basically as readable as the asserts, especially since the testing function has been renamed. ETA: someone else is welcome to override me on this or argue that I can open up a PR to parameterize these tests myself. |
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 the nonparametrized form is just fine.
I also think the tests are better not being parameterized. Parameterizing is great if you have a matrix of things you are testing, but otherwise I think they are needlessly hard to read. I'm not sure I understand the "overview of all the problems" idea - that sounds like a theoretical rather than practical concern. |
.. further, if you parameterize the tests, it is a lot more work to move the test to a separate script for debugging, which is something I do all the time to bypass all the py.test verbiage |
@jklymak since the test fails on the first assert, you won't know if your code broke on the other types of input until you fix that one first. That means you have to go down the line individually when sometimes getting a sense of all the conditions on which it fails (or that it fails multiple conditions) is better for pinpointing what went wrong. |
@story645 "getting a sense of all the conditions on which it fails" is nice in theory. However, in practice the pytest output is so unwieldy that it's hard to grasp that overview. To illustrate, I've introduced an error and posted the pytest logs for both variants below. Additionally, often multiple tests fail for the same reason, in which case the multiple failures don't give additional insight and are only clutter. And if they fail for different reasons, often one has to address these reasons separately. Non-parametrized test
Parametrized test
|
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.
Ok, even I don't want to be blocking on stuff I think should be addressed in a later PR.
PR Summary
Closes #18731.
This allows
instead of the verbose