-
Notifications
You must be signed in to change notification settings - Fork 19
Implementing skip_blank option #37
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
Here's a different possibility when multiple lines are skipped:
I admit that it is a bit of a contrived examples, as there are rarely two blank lines in the code, except before functions and class definitions. Still, I have a slight preference for this one, using only Edit:Note that I have not made a change to the committed code to reflect this last example. |
stack_data/core.py
Outdated
@@ -521,6 +534,10 @@ def __init__( | |||
self.code = frame.f_code | |||
self.options = options or Options() # type: Options | |||
self.source = self.executing.source # type: Source | |||
if hasattr(self.options, "skip_blank"): |
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 don't think we need to account for self.options
being the wrong type. I also don't think we need a FrameInfo.skip_blank
attribute/property anyway - self.options.skip_blank
seems fine.
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, for not checking that self.options
has the correct type. If I use an enum, or something else with three options for skip_blank
, I will have to do a test of some kind.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
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, I clicked on resolved by accident and forgot about 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.
This should now have been taken care of.
You could add a |
|
btw |
…wing line numbers.
While everything seems to work correctly, more improvements to the code needs to be done. I will try to finish it tomorrow. |
Other than missing unit tests, I believe that this is now ready. To illustrate the effect of each option, I will use the following example which includes many blank lines:
Default outputThe default is the current behaviour of
Making empty lines "visible" as text.Setting the following parameters:
The result is as follows:
Using only line number "markers" to indicate blank lines.Setting the following parameters:
gives the following result (notice that
Setting a different string for blank lines that are "skipped".Using the following parameters
gives the following result:
Added explanation for a comment.Using the default values, here's what happen if I were to remove the following code in
Here is the result:
Notice how, due to the blank line 10 in the marked executing piece, the markers on lines 11 and 12 extend all the way back to the first column. Minor cosmetic bug fixIn
If the
Notice the gap between lines 10 and 11 in the marked piece. |
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, this is looking pretty good. My points are minor, the biggest remaining thing is the tests.
stack_data/core.py
Outdated
@@ -521,6 +534,10 @@ def __init__( | |||
self.code = frame.f_code | |||
self.options = options or Options() # type: Options | |||
self.source = self.executing.source # type: Source | |||
if hasattr(self.options, "skip_blank"): |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Co-authored-by: Alex Hall <alex.mojaki@gmail.com>
Co-authored-by: Alex Hall <alex.mojaki@gmail.com>
The code coverage has slightly decreased due to:
Are unit tests needed for these two cases? |
The first point seems trivial to test. Just construct a bad formatter and assert the raised exception. No need to do any formatting. I don't know what the second point means. |
@@ -168,7 +179,7 @@ def format_line(self, line: Line) -> str: | |||
result += " " | |||
|
|||
if self.show_linenos: | |||
result += "{:4} | ".format(line.lineno) | |||
result += self.line_number_format_string.format(line.lineno) |
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 this new option? It seems unrelated to the rest of the PR. And shouldn't it be used in format_blank_lines_linenumbers
?
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 added it as the indentation was fixed and I might want a larger value in friendly_traceback; it is the only hard-coded value you had in stack_data, while all the others could be changed by the users. And, yes, I overlooked the fact that it should have been used in format_blank_lines_linenumbers
as well. I will need to do this.
if self.current_line_indicator: | ||
result = " " * len(self.current_line_indicator) | ||
else: | ||
result = " " |
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.
https://coveralls.io/builds/51814297/source?filename=stack_data%2Fformatting.py#L214 points out that this line is uncovered, and it seems worth testing.
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. I probably won't have time to do this tonight 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.
I had added this else
part based on the presence of the second term in
stack_data/stack_data/formatting.py
Line 173 in 7e88082
result = result or " " |
However, it turns out that
result
was never null and that this line was redundant in the original code, based on all existing tests. So I removed the corresponding else
part of my addition.
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.
It's pretty easy to see when the line isn't redundant in the previous code: when you set show_linenos=False, current_line_indicator=""
. result
won't be null, it'll be an empty string. Defaulting it to spaces ensures that the user's code is indented like in a standard traceback. I guess it should have been tested before, but coverage didn't see the gap.
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.
Do you want me to reinstate it and write a relevant test 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.
Yes please.
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 there's been some confusion or misremembering. The test needs to specifically have both the arguments show_linenos=False, current_line_indicator=""
in one formatter.
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, I was wondering why the line result = result or " "
did not seem to have any effect. I will fix this.
|
tests/test_formatter.py
Outdated
try: | ||
MyFormatter(show_linenos=False, options=Options(blank_lines=BlankLines.SINGLE)) | ||
except ValueError: | ||
assert True | ||
else: | ||
assert False |
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.
try: | |
MyFormatter(show_linenos=False, options=Options(blank_lines=BlankLines.SINGLE)) | |
except ValueError: | |
assert True | |
else: | |
assert False | |
with pytest.raises(ValueError): | |
MyFormatter(show_linenos=False, options=Options(blank_lines=BlankLines.SINGLE)) |
and an import pytest
at the top.
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 do.
@@ -166,12 +177,13 @@ def format_line(self, line: Line) -> str: | |||
else: | |||
result = " " * len(self.current_line_indicator) | |||
result += " " | |||
else: |
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 this should be removed, the original line result = result or " "
is enough. A test without current_line_indicator
but with show_linenos
would confirm.
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 are, of course, correct. I had a brain freeze when I added this.
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 tested this by creating two additional tests (with or without blank lines included). Do you want these extra tests added in a commit?
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've already written the test etc. then might as well. But no need for extra effort. Just remove these two lines, unless the tests show otherwise.
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 two lines, the result is as follows:
Traceback (most recent call last):
File "formatter_example.py", line 85, in blank_lines
79 | def blank_lines():
80 | a = [1, 2, 3]
82 | length = len(a)
85 | return a[length]
^^^^^^^^^
IndexError: list index out of range
Without them, the indentation is slightly less
Traceback (most recent call last):
File "formatter_example.py", line 85, in blank_lines
79 | def blank_lines():
80 | a = [1, 2, 3]
82 | length = len(a)
85 | return a[length]
^^^^^^^^^
IndexError: list index out of range
Which one do you prefer? Once decided, it probably would make sense to include the tests.
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.
Oh, it looks nicer with the extra spaces, I didn't expect that. Especially if the line numbers reach 4 digits. So let's go with the former option, and then I think result = result or " "
isn't 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.
I needed to modified the code when using blank_lines.HIDDEN
with no current line marker so that it would be consistent with the others. I added three tests, one for each setting.
…no current line marker.
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.
All looks good, thanks! Happy for me to merge?
Yes, please do! |
I've implemented the
skip_blank
option by adding a new line type, and adding a newOption
.Here's an example where the default (skipping blank lines) is used:
And here's an example where
skip_blank
is set toFalse
: