Skip to content

Commit

Permalink
Merge pull request #48 from life4/mypy
Browse files Browse the repository at this point in the history
Run MyPy on CI
  • Loading branch information
orsinium committed Apr 21, 2020
2 parents 8c30809 + 94e208f commit 4da4ce9
Show file tree
Hide file tree
Showing 50 changed files with 284 additions and 81 deletions.
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,8 @@ matrix:
env: ENV=flake8
script:
- dephell venv run --env=$ENV

- python: "3.7"
env: ENV=typing
script:
- dephell venv run --env=$ENV
4 changes: 2 additions & 2 deletions deal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
pre, pure, raises, reason, require, safe, silent,
)
from ._exceptions import * # noQA
from ._imports import activate, module_load
from ._schemes import Scheme
from ._state import reset, switch
from ._imports import module_load, activate
from ._testing import TestCase, cases


Expand All @@ -46,14 +46,14 @@
'offline',
'post',
'pre',
'pure',
'raises',
'reason',
'safe',
'silent',

# aliases
'invariant',
'pure',
'require',

# module level
Expand Down
11 changes: 7 additions & 4 deletions deal/_decorators/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
from asyncio import iscoroutinefunction
from contextlib import suppress
from functools import update_wrapper
from typing import Callable, Type
from typing import Callable

# external
import vaa

# app
Expand All @@ -16,8 +17,8 @@
class Base:
exception: ExceptionType = ContractError

def __init__(self, validator: Callable, *, message: str = None,
exception: Type[ExceptionType] = None, debug: bool = False):
def __init__(self, validator, *, message: str = None,
exception: ExceptionType = None, debug: bool = False):
"""
Step 1. Set contract (validator).
"""
Expand All @@ -29,7 +30,9 @@ def __init__(self, validator: Callable, *, message: str = None,
self.exception = self.exception(message) # type: ignore

@staticmethod
def _make_validator(validator, message: str):
def _make_validator(validator, message: str = None):
if validator is None:
return None
# implicitly wrap in vaa all external validators
with suppress(TypeError):
return vaa.wrap(validator, simple=False)
Expand Down
6 changes: 3 additions & 3 deletions deal/_decorators/inv.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def __setattr__(self, name: str, value):
class Invariant(Base):
exception: ExceptionType = InvContractError

def validate(self, obj) -> None:
def validate(self, obj) -> None: # type: ignore
"""
Step 6. Process contract (validator)
"""
Expand All @@ -81,15 +81,15 @@ def validate_chain(self, *args, **kwargs) -> None:
self.validate(*args, **kwargs)
self.child_validator(*args, **kwargs)

def __call__(self, _class: type):
def __call__(self, _class: type): # type: ignore
"""
Step 2. Return wrapped class.
"""
# patch class parents and add method for validation

# if already invarianted
if hasattr(_class, '_validate_base'):
self.child_validator = _class._validate_base
self.child_validator = _class._validate_base # type: ignore
patched_class = type(
_class.__name__,
(_class, ),
Expand Down
2 changes: 1 addition & 1 deletion deal/_decorators/offline.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def __init__(self, *, message: str = None, exception: ExceptionType = None, debu
Step 1. Init params.
"""
super().__init__(
validator=None,
validator=None, # type: ignore
message=message,
exception=exception,
debug=debug,
Expand Down
2 changes: 1 addition & 1 deletion deal/_decorators/raises.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def __init__(self, *exceptions, message: str = None, exception: ExceptionType =
"""
self.exceptions: Tuple[Type[Exception], ...] = exceptions
super().__init__(
validator=None,
validator=None, # type: ignore
message=message,
exception=exception,
debug=debug,
Expand Down
25 changes: 14 additions & 11 deletions deal/_imports.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# built-in
import ast
import sys
from _frozen_importlib_external import PathFinder
from types import ModuleType
from typing import Callable, Optional, List
from typing import Any, Callable, List, Optional

from .linter._extractors.common import get_name
# project
from _frozen_importlib_external import PathFinder

# app
from . import _aliases
from ._state import state
from .linter._extractors.common import get_name


def _enabled(debug: bool = False) -> bool:
Expand Down Expand Up @@ -60,10 +63,10 @@ def exec_module(self, module: ModuleType) -> None:

@staticmethod
def _get_contracts(tree: ast.Module) -> List[ast.AST]:
for node in tree.body:
if not type(node) is ast.Expr:
for node in tree.body: # type: Any
if type(node) is not ast.Expr:
continue
if not type(node.value) is ast.Call:
if type(node.value) is not ast.Call:
continue
if get_name(node.value.func) != 'deal.module_load':
continue
Expand All @@ -74,12 +77,12 @@ def _get_contracts(tree: ast.Module) -> List[ast.AST]:
def _exec_contract(cls, node: ast.AST) -> Optional[Callable]:
"""Get AST node and return a contract function
"""
if type(node) is ast.Call and not node.args:
return cls._exec_contract(node.func)
if type(node) is ast.Call and not node.args: # type: ignore
return cls._exec_contract(node.func) # type: ignore

if not isinstance(node, ast.Attribute):
return None
if node.value.id != 'deal':
if node.value.id != 'deal': # type: ignore
return None
contract = getattr(_aliases, node.attr, None)
if contract is None:
Expand Down Expand Up @@ -109,7 +112,7 @@ def activate(debug: bool = False) -> bool:
if DealFinder in sys.meta_path:
return False
index = sys.meta_path.index(PathFinder)
sys.meta_path[index] = DealFinder
sys.meta_path[index] = DealFinder # type: ignore
return True


Expand All @@ -118,6 +121,6 @@ def deactivate() -> bool:
"""
if DealFinder not in sys.meta_path:
return False
index = sys.meta_path.index(DealFinder)
index = sys.meta_path.index(DealFinder) # type: ignore
sys.meta_path[index] = PathFinder
return True
1 change: 1 addition & 0 deletions deal/linter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# app
from ._checker import Checker


Expand Down
3 changes: 3 additions & 0 deletions deal/linter/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# built-in
import sys

# app
from ._cli import main


if __name__ == '__main__':
exit(main(sys.argv[1:]))
29 changes: 20 additions & 9 deletions deal/linter/_checker.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
# built-in
import ast
import typing
from pathlib import Path

from astroid import AstroidSyntaxError

# app
from ._error import Error
from ._func import Func
from ._rules import rules, Required
from ._rules import Required, rules


class Checker:
name = 'deal'
version = '1.0.0'
_tree = None
_rules = rules

def __init__(self, tree: ast.AST, file_tokens=None, filename: str = 'stdin'):
def __init__(self, tree: ast.Module, file_tokens=None, filename: str = 'stdin'):
self._tree = tree
self._filename = filename

@property
def version(self):
import deal

return deal.__version__

def run(self) -> typing.Iterator[tuple]:
for error in self.get_errors():
yield tuple(error) + (type(self),) # type: ignore

def get_errors(self) -> typing.Iterator[Error]:
def get_funcs(self) -> typing.List['Func']:
if self._filename == 'stdin':
funcs = Func.from_ast(tree=self._tree)
else:
funcs = Func.from_path(path=Path(self._filename))
return Func.from_ast(tree=self._tree)
try:
return Func.from_path(path=Path(self._filename))
except AstroidSyntaxError:
return Func.from_ast(tree=self._tree)

for func in funcs:
def get_errors(self) -> typing.Iterator[Error]:
for func in self.get_funcs():
for rule in self._rules:
if rule.required != Required.FUNC:
continue
Expand Down
6 changes: 4 additions & 2 deletions deal/linter/_cli.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# built-in
import ast
import json
from argparse import ArgumentParser
from pathlib import Path
from textwrap import dedent, indent
from typing import Iterable, Iterator, Union
from typing import Iterable, Iterator, Sequence, Union

# app
from ._checker import Checker


Expand Down Expand Up @@ -65,7 +67,7 @@ def get_parser() -> ArgumentParser:
return parser


def main(argv: Iterable) -> int:
def main(argv: Sequence[str]) -> int:
parser = get_parser()
args = parser.parse_args(argv)
prev = None
Expand Down
3 changes: 3 additions & 0 deletions deal/linter/_contract.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# built-in
import ast
import builtins
import enum

# external
import astroid

# app
from ._extractors import get_name


Expand Down
2 changes: 2 additions & 0 deletions deal/linter/_error.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# built-in
import typing


ERROR_FORMAT = 'DEAL{code:03d}: {text}'


Expand Down
1 change: 1 addition & 0 deletions deal/linter/_extractors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# app
from .common import get_name
from .contracts import get_contracts
from .exceptions import get_exceptions
Expand Down
12 changes: 10 additions & 2 deletions deal/linter/_extractors/common.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# built-in
import ast
from types import SimpleNamespace
from typing import Optional

# external
import astroid


Expand Down Expand Up @@ -57,8 +59,14 @@ def get_name(expr) -> Optional[str]:
return expr.name

if isinstance(expr, astroid.Attribute):
return get_name(expr.expr) + '.' + expr.attrname
left = get_name(expr.expr)
if left is None:
return None
return left + '.' + expr.attrname
if isinstance(expr, ast.Attribute):
return get_name(expr.value) + '.' + expr.attr
left = get_name(expr.value)
if left is None:
return None
return left + '.' + expr.attr

return None
7 changes: 5 additions & 2 deletions deal/linter/_extractors/contracts.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from typing import Tuple, Iterator
# built-in
from typing import Iterator, Tuple

# external
import astroid

from .common import get_name, TOKENS
# app
from .common import TOKENS, get_name


SUPPORTED_CONTRACTS = {'deal.post', 'deal.raises', 'deal.silent'}
Expand Down
12 changes: 9 additions & 3 deletions deal/linter/_extractors/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# built-in
import ast
import builtins
from typing import Iterator

# external
import astroid

from .common import traverse, Token, TOKENS, get_name
# app
from .common import TOKENS, Token, get_name, traverse


def get_exceptions(body: list, *, dive: bool = True) -> Iterator[Token]:
Expand All @@ -19,8 +22,11 @@ def get_exceptions(body: list, *, dive: bool = True) -> Iterator[Token]:
# explicit raise
if isinstance(expr, TOKENS.RAISE):
name = get_name(expr.exc)
# raise instance
if not name and isinstance(expr.exc, TOKENS.CALL):
if not name:
# raised a value, too tricky
if not isinstance(expr.exc, TOKENS.CALL):
continue
# raised an instance of an exception
name = get_name(expr.exc.func)
if not name or name[0].islower():
continue
Expand Down
5 changes: 4 additions & 1 deletion deal/linter/_extractors/imports.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# built-in
import ast
from typing import Iterator

# external
import astroid

from .common import traverse, Token
# app
from .common import Token, traverse


def get_imports(body: list) -> Iterator[Token]:
Expand Down
5 changes: 4 additions & 1 deletion deal/linter/_extractors/prints.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# built-in
import ast
from typing import Iterator

# external
import astroid

from .common import Token, get_name, traverse, TOKENS
# app
from .common import TOKENS, Token, get_name, traverse


def get_prints(body: list) -> Iterator[Token]:
Expand Down

0 comments on commit 4da4ce9

Please sign in to comment.