Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions shopify_python/google_styleguide.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class GoogleStyleGuideChecker(checkers.BaseChecker):
'lambda-func',
"For common operations like multiplication, use the functions from the operator module"
"instead of lambda functions. For example, prefer operator.mul to lambda x, y: x * y."),
'C6015': ('No blank line after a class definition',
'blank-line-after-class-required',
'Missing a blank line after a class definition'),
}

options = (
Expand Down Expand Up @@ -173,6 +176,9 @@ def visit_raise(self, node): # type: (astroid.Raise) -> None
def visit_if(self, node):
self.__use_cond_expr(node) # type: (astroid.If) -> None

def visit_classdef(self, node): # type: (astroid.ClassDef) -> None
self.__class_def_check(node)

@staticmethod
def __get_module_names(node): # type: (astroid.ImportFrom) -> typing.Generator[str, None, None]
for name in node.names:
Expand Down Expand Up @@ -322,3 +328,17 @@ def __lambda_func(self, node): # type: (astroid.Lambda) -> None
lambda_fun = "lambda " + left + ', ' + right + ": " + " ".join([left, node.ops[0][0], right])
op_fun = "operator." + operator
self.add_message('lambda-func', node=node, args={'op': op_fun, 'lambda_fun': lambda_fun})

def __class_def_check(self, node): # type: (astroid.ClassDef) -> None
"""Enforce a blank line after a class definition line."""
prev_line = node.lineno

for element in node.body:
curr_line = element.lineno
blank_lines = curr_line - prev_line - 1
if isinstance(element, astroid.FunctionDef) and blank_lines < 1:
self.add_message('blank-line-after-class-required', node=node)
break
elif isinstance(element, astroid.FunctionDef):
break
prev_line = curr_line
4 changes: 4 additions & 0 deletions tests/functional/blank_line_after_class_required.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# pylint:disable=missing-docstring,invalid-name,too-few-public-methods
class SomeClass(object): # [blank-line-after-class-required]
def apply(self):
pass
1 change: 1 addition & 0 deletions tests/functional/blank_line_after_class_required.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
blank-line-after-class-required:2:SomeClass:No blank line after a class definition
46 changes: 46 additions & 0 deletions tests/shopify_python/test_google_styleguide.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,49 @@ def binaryfnc():
""".format(expression))
with self.assertNoMessages():
self.walk(binary_root)

def test_class_def_blank_line(self):
root = astroid.builder.parse("""
class SomePipeline(object):
def apply(content):
return content.withColumn('zero', F.lit(0.0))

class Fact(object):
INPUTS = {}
def apply(self):
pass

class Stage(object):
INPUTS = {}

OUTPUTS = {}
def apply(self):
pass
""")
with self.assertAddsMessages(
*[pylint.testutils.Message('blank-line-after-class-required', node=root.body[0]),
pylint.testutils.Message('blank-line-after-class-required', node=root.body[1]),
pylint.testutils.Message('blank-line-after-class-required', node=root.body[2])]
):
self.walk(root)

with self.assertNoMessages():
self.walk(astroid.builder.parse("""
class SomePipeline(object):

def apply(content):
return content.withColumn('zero', F.lit(0.0))

class FirstStage(object):
pass

class SecondStage(object):
INPUTS = {}
OUTPUTS = {}

def check():
pass

def apply():
pass
"""))