Skip to content

Commit

Permalink
report @pure functions without return or yield
Browse files Browse the repository at this point in the history
  • Loading branch information
orsinium committed May 4, 2020
1 parent 3c8c676 commit a0cb6bd
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 5 deletions.
5 changes: 3 additions & 2 deletions deal/linter/_extractors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@
from .globals import get_globals
from .imports import get_imports
from .prints import get_prints
from .returns import get_returns
from .returns import get_returns, has_returns


__all__ = [
'get_asserts',
'get_contracts',
'get_exceptions',
'get_exceptions_stubs',
'get_exceptions',
'get_globals',
'get_imports',
'get_name',
'get_prints',
'get_returns',
'has_returns',
]
1 change: 1 addition & 0 deletions deal/linter/_extractors/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
TRY=(ast.Try, astroid.TryExcept, astroid.TryFinally),
UNARY_OP=(ast.UnaryOp, astroid.UnaryOp),
WITH=(ast.With, astroid.With),
YIELD=(ast.Yield, astroid.Yield),
)


Expand Down
9 changes: 8 additions & 1 deletion deal/linter/_extractors/returns.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@
import astroid

# app
from .common import TOKENS, Extractor, Token, infer
from .common import TOKENS, Extractor, Token, infer, traverse


get_returns = Extractor()
inner_extractor = Extractor()


def has_returns(body: list) -> bool:
for expr in traverse(body=body):
if isinstance(expr, TOKENS.RETURN + TOKENS.YIELD):
return True
return False


@get_returns.register(*TOKENS.RETURN)
def handle_returns(expr) -> Optional[Token]:
# inner_extractor
Expand Down
10 changes: 8 additions & 2 deletions deal/linter/_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@


class Func:
__slots__ = ('body', 'contracts', 'name')
__slots__ = ('body', 'contracts', 'name', 'line', 'col')

def __init__(self, *, body: list, contracts: Iterable[Contract], name: str):
def __init__(self, *, body: list, contracts: Iterable[Contract], name: str, line: int, col: int):
self.body = body
self.contracts = contracts
self.name = name
self.line = line
self.col = col

@classmethod
def from_path(cls, path: Path) -> List['Func']:
Expand All @@ -50,6 +52,8 @@ def from_ast(cls, tree: ast.Module) -> List['Func']:
name=expr.name,
body=expr.body,
contracts=contracts,
line=expr.lineno,
col=expr.col_offset,
))
return funcs

Expand All @@ -68,6 +72,8 @@ def from_astroid(cls, tree: astroid.Module) -> List['Func']:
name=expr.name,
body=expr.body,
contracts=contracts,
line=expr.lineno,
col=expr.col_offset,
))
return funcs

Expand Down
9 changes: 9 additions & 0 deletions deal/linter/_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ._extractors import (
get_exceptions, get_exceptions_stubs, get_globals,
get_imports, get_prints, get_returns, get_asserts,
has_returns,
)
from ._func import Func
from ._stub import StubsManager
Expand Down Expand Up @@ -158,6 +159,14 @@ def __call__(self, func: Func, stubs: StubsManager = None) -> Iterator[Error]:
return

def _check(self, func: Func, stubs: StubsManager = None) -> Iterator[Error]:
if not has_returns(body=func.body):
yield Error(
code=self.code,
text=self.message,
value='return',
row=func.line,
col=func.col,
)
for token in get_globals(body=func.body):
yield Error(
code=self.code,
Expand Down
1 change: 1 addition & 0 deletions tests/test_linter/test_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ def test_check_pure():
@deal.pure
def test(a):
global b
return b
"""
text = dedent(text).strip()
funcs1 = Func.from_ast(ast.parse(text))
Expand Down

0 comments on commit a0cb6bd

Please sign in to comment.