-
Notifications
You must be signed in to change notification settings - Fork 751
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
Fix Issue 400: Require two blank lines after toplevel def, class #536
Conversation
Thanks! This looks good to me. Could you add a note in the CHANGELOG before I merge it? Mentioning that its a change which adds a new check (E305) ? Also, you'll need to update the error codes table in the docs to include this new error code. |
@@ -270,6 +272,9 @@ def blank_lines(logical_line, blank_lines, indent_level, line_number, | |||
yield 0, "E301 expected 1 blank line, found 0" | |||
elif blank_before != 2: | |||
yield 0, "E302 expected 2 blank lines, found %d" % blank_before | |||
elif (logical_line and not indent_level and blank_before != 2 and | |||
previous_logical_toplevel.startswith(('def', 'class'))): | |||
yield 0, "E305 expected 2 blank lines before, found %d" % blank_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.
What about changing the message to be:
E305 expected 2 blank lines after class or function definition, found %d
It would be more reusable if it was a list of all previous logical lines, and the check function finds the relevant previous lines. |
@jayvdb why would it be more useful? I see no practical value in storing every completely non-indented logical line in a file. |
@sigmavirus24 , who suggested storing non-indented logical lines? That would be silly, bordering on bizarre, as that isnt what pycodestyle currently builds and provides to checkers. I believe it will be useful to have all of the logical lines available in order to solve other edge cases in pycodestyle (like this one) and checkers not part of the pycodestyle package. The rationale is the Zero one infinity rule. There is a small mostly theoretical memory footprint cost of keeping the previous logical lines already created, linear with file size, but that cost is only a real serious cost if the previous logical lines are garbage collected during the processing of one file, which I havent noticed even on fairly large source files being processed on a normal system. For a bare-bones implementation, the remaining footprint cost would be the list of logical lines each stored as a tuple with an int and a pointer to a str. Additional logical line attributes (that are already currently computed) could be added to the tuple, and each logical line could be a dict instead of a tuple for a nicer interface for backwards compatibility if another attribute is added. If others generally agree that a list of previous logical lines would be good, I'd be happy to write up a new issue where the nuts and bolts can be discussed. If we want to get this patch in and refactor later, the attribute could be called |
This patch currently only stores the previous non-indented logical line. This is not storing the previous logical line because the Checker already does that. Currently pycodestyle is already following the Zero one infinity rule in that regard. What we're talking about in this patch is storing the previous non-indented logical line. So in the context of this patch, I understood your suggestion to be about storing all non-indented logical lines.
This isn't an edge case of not having all previous logical lines. This is an edge case where we need to know what the last non-indented logical line was. You're confusing the discussion on this patch. Until we have found these other edge cases, I'm against adding the complete list of logical lines in a file, merely in an effort to keep pycodestyle as performant as it can be. (Appending to an ever growing list would work against that very effort.)
So you've tested this and can share the tests separately?
I really think this discussion is completely orthogonal to this pull request and here's why:
So please, let's curb this side discussion that is not helping @ArcTanSusan or the other reviewers. |
Ok, coming at this from a different direction in the hope we can find consensus that Checker attributes for special cases are bad design. "Top level" as a concept is ambiguous. It may change. I've left a comment on #400 about this, so discussion about the PEP can continue there. We shouldnt have public Checker state attributes that implement specific check logic. That creates backwards compatibility problems, as the PEP does evolve over time. If this is going to add a Checker state attribute for the most recent last logical line without any indent, we should name it accordingly. say no_indent_logical_line |
So with the definition of "top-level" as meaning "global scope" we should be enforcing this in the following cases: def foo(): pass
def bar(): pass
class Foo: pass
class Bar: pass
if __name__ == '__main__':
foo() We should also be enforcing this here: if c_ext:
class Foo(c_ext.Foo): pass
class Bar(c_ext.Bar): pass
else:
class Foo(object): pass
class Bar(object): pass
if some_other_cond:
def biz(): pass Presently, the way pycodestyle works we track indentation and not scope. I think it's also clear that this pull request is an improvement (but not a complete fix) for #400. I also support @jayvdb's suggested name of The logic for determining if we're in a global scope (based on what tools already exist for pycodestyle) will be tricky so we'll have to test it thoroughly and comment it well to prevent it from breaking in the future. We will probably also want to use private state to update the attribute for determining our current scope. (To be clear, I don't think we need anything other than "yes we're defining a function/class in global state" and "no we're not".) |
fwiw, I think we should proceed with a new private attribute (prefixed with Then we can come up with a more complex solution for the indented definitions and all that entails (#366 would seem like a good place to track that), and back out the private attribute at the same time. |
@@ -23,6 +23,7 @@ Changes: | |||
* Added check E275 for whitespace on `from ... import ...` lines; #489 / #491 | |||
* Added W503 to the list of codes ignored by default ignore list; #498 | |||
* Removed use of project level `.pep8` configuration file; #364 | |||
* Added check E305 for two blank lines after toplevel method and toplevel class; #400 |
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 actually be up in the unreleased next version changes section.
Thanks, @ArcTanSusan! 🍻 |
In particular PyCQA/pycodestyle#536 which landed as part of 2.1.0 today (https://github.com/PyCQA/pycodestyle/blob/2.2.0/CHANGES.txt#L15) finds one place where there should have been another newline.
In particular PyCQA/pycodestyle#536 which landed as part of 2.1.0 today (https://github.com/PyCQA/pycodestyle/blob/2.2.0/CHANGES.txt#L15) finds one place where there should have been another newline.
In particular PyCQA/pycodestyle#536 which landed as part of 2.1.0 today (https://github.com/PyCQA/pycodestyle/blob/2.2.0/CHANGES.txt#L15) finds one place where there should have been another newline.
2.2.0 (2016-11-14) ------------------ Bugs: * Fixed E305 regression caused by PyCQA#400; PyCQA#593 2.1.0 (2016-11-04) ------------------ Changes: * Report E302 for blank lines before an "async def"; PyCQA#556 * Update our list of tested and supported Python versions which are 2.6, 2.7, 3.2, 3.3, 3.4 and 3.5 as well as the nightly Python build and PyPy. * Report E742 and E743 for functions and classes badly named 'l', 'O', or 'I'. * Report E741 on 'global' and 'nonlocal' statements, as well as prohibited single-letter variables. * Deprecated use of `[pep8]` section name in favor of `[pycodestyle]`; PyCQA#591 Bugs: * Fix opt_type AssertionError when using Flake8 2.6.2 and pycodestyle; PyCQA#561 * Require two blank lines after toplevel def, class; PyCQA#536 * Remove accidentally quadratic computation based on the number of colons. This will make pycodestyle faster in some cases; PyCQA#314 2.0.0 (2016-05-31) ------------------ Changes: * Added tox test support for Python 3.5 and pypy3 * Added check E275 for whitespace on `from ... import ...` lines; PyCQA#489 / PyCQA#491 * Added W503 to the list of codes ignored by default ignore list; PyCQA#498 * Removed use of project level `.pep8` configuration file; PyCQA#364 Bugs: * Fixed bug with treating `~` operator as binary; PyCQA#383 / PyCQA#384 * Identify binary operators as unary; PyCQA#484 / PyCQA#485 1.7.0 (2016-01-12) ------------------ Changes: * Reverted the fix in PyCQA#368, "options passed on command line are only ones accepted" feature. This has many unintended consequences in pep8 and flake8 and needs to be reworked when I have more time. * Added support for Python 3.5. (Issue PyCQA#420 & PyCQA#459) * Added support for multi-line config_file option parsing. (Issue PyCQA#429) * Improved parameter parsing. (Issues PyCQA#420 & PyCQA#456) Bugs: * Fixed BytesWarning on Python 3. (Issue PyCQA#459)
The original author wrote #402 to fix #400, which has been in-active since August 2015. I've rebased the commits and squashed the work into 1 commit here.