Skip to content

Commit

Permalink
Merge 81f46fe into f85cefe
Browse files Browse the repository at this point in the history
  • Loading branch information
orsinium committed Apr 30, 2020
2 parents f85cefe + 81f46fe commit 91c5ba0
Show file tree
Hide file tree
Showing 159 changed files with 6,699 additions and 85 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# python
*.pyc
__pycache__/
*.egg-info/
dist/

# coverage
.coverage*
coverage.xml
htmlcov/

# other
README.rst
docs/build/
/setup.py
Expand Down
9 changes: 9 additions & 0 deletions deal/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# built-in
import sys

# app
from ._cli import main


if __name__ == '__main__':
exit(main(sys.argv[1:]))
5 changes: 5 additions & 0 deletions deal/_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# app
from ._main import main


__all__ = ['main']
6 changes: 3 additions & 3 deletions deal/linter/_cli.py → deal/_cli/_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from typing import Iterable, Iterator, Sequence, Union

# app
from ._checker import Checker
from ..linter import Checker


COLORS = dict(
Expand Down Expand Up @@ -61,13 +61,13 @@ def get_errors(paths: Iterable[Union[str, Path]]) -> Iterator[dict]:


def get_parser() -> ArgumentParser:
parser = ArgumentParser()
parser = ArgumentParser(prog='python3 -m deal lint')
parser.add_argument('--json', action='store_true', help='json output')
parser.add_argument('paths', nargs='*', default='.')
return parser


def main(argv: Sequence[str]) -> int:
def lint_command(argv: Sequence[str]) -> int:
parser = get_parser()
args = parser.parse_args(argv)
prev = None
Expand Down
24 changes: 24 additions & 0 deletions deal/_cli/_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# built-in
from argparse import ArgumentParser
from types import MappingProxyType
from typing import Callable, Mapping, Sequence

# app
from ._lint import lint_command
from ._stub import stub_command


CommandsType = Mapping[str, Callable[[Sequence[str]], int]]
COMMANDS: CommandsType = MappingProxyType(dict(
lint=lint_command,
stub=stub_command,
))


def main(argv: Sequence[str], *, commands: CommandsType = COMMANDS) -> int:
parser = ArgumentParser(prog='python3 -m deal')
parser.add_argument('command', choices=sorted(commands))

args, unknown_argv = parser.parse_known_args(argv)
command = commands[args.command]
return command(unknown_argv)
23 changes: 23 additions & 0 deletions deal/_cli/_stub.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# built-in
from argparse import ArgumentParser
from pathlib import Path
from typing import Sequence

# app
from ..linter import StubsManager, generate_stub


def stub_command(argv: Sequence[str]) -> int:
parser = ArgumentParser(prog='python3 -m deal stub')
parser.add_argument('--iterations', type=int, default=1)
parser.add_argument('paths', nargs='+')
args = parser.parse_args(argv)

paths = [Path(path) for path in args.paths]
roots = list(StubsManager.default_paths) + list(set(paths))
stubs = StubsManager(paths=roots)

for _ in range(args.iterations):
for path in paths:
generate_stub(path=path, stubs=stubs)
return 0
2 changes: 2 additions & 0 deletions deal/_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ def find_spec(cls, *args, **kwargs):


class DealLoader:
__slots__ = ('_loader', )

def __init__(self, loader):
self._loader = loader

Expand Down
2 changes: 2 additions & 0 deletions deal/_state.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@


class _State:
__slots__ = ('main', 'debug')

def __init__(self):
self.reset()

Expand Down
2 changes: 1 addition & 1 deletion deal/_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def pass_along_variables(*args, **kwargs) -> ArgsKwargsType:
def example_generator(ex: ArgsKwargsType) -> None:
examples.append(ex)

example_generator()
example_generator() # pylint: disable=no-value-for-parameter
return examples


Expand Down
3 changes: 2 additions & 1 deletion deal/linter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# app
from ._checker import Checker
from ._stub import StubsManager, generate_stub


__all__ = ['Checker']
__all__ = ['Checker', 'StubsManager', 'generate_stub']
4 changes: 2 additions & 2 deletions deal/linter/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import sys

# app
from ._cli import main
from .._cli._lint import lint_command


if __name__ == '__main__':
exit(main(sys.argv[1:]))
exit(lint_command(sys.argv[1:]))
17 changes: 15 additions & 2 deletions deal/linter/_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,23 @@
from ._error import Error
from ._func import Func
from ._rules import Required, rules
from ._stub import StubsManager


class Checker:
__slots__ = ('_tree', '_filename', '_stubs')
name = 'deal'
_rules = rules

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

paths = list(StubsManager.default_paths)
if filename != 'stdin':
paths.append(Path(filename).absolute().parent)
self._stubs = StubsManager(paths=paths)

@property
def version(self):
import deal
Expand All @@ -39,13 +46,19 @@ def get_funcs(self) -> typing.List['Func']:
return Func.from_ast(tree=self._tree)

def get_errors(self) -> typing.Iterator[Error]:
reported = set()
for func in self.get_funcs():
for rule in self._rules:
if rule.required != Required.FUNC:
continue
yield from rule(func)
for error in rule(func=func, stubs=self._stubs):
hs = hash(error)
if hs in reported:
continue
reported.add(hs)
yield error

for rule in self._rules:
if rule.required != Required.MODULE:
continue
yield from rule(self._tree)
yield from rule(tree=self._tree)
7 changes: 4 additions & 3 deletions deal/linter/_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
# external
import astroid

# app
from ._extractors import get_name


TEMPLATE = """
contract = PLACEHOLDER
Expand All @@ -24,6 +21,8 @@ class Category(enum.Enum):


class Contract:
__slots__ = ('args', 'category')

def __init__(self, args, category: Category):
self.args = args
self.category = category
Expand Down Expand Up @@ -54,6 +53,8 @@ def _resolve_name(contract):

@property
def exceptions(self) -> list:
from ._extractors import get_name

excs = []
for expr in self.args:
name = get_name(expr)
Expand Down
13 changes: 10 additions & 3 deletions deal/linter/_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
import typing


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


class Error:
__slots__ = ('row', 'col', 'code', 'text', 'value')

def __init__(self, *, row: int, col: int, code: int, text: str, value: str = None):
self.row = row
self.col = col
Expand All @@ -29,7 +31,12 @@ def __str__(self) -> str:
return self.message

def __repr__(self) -> str:
return '{name}({content!r})'.format(
return '{name}(row={row}, col={col}, code={code})'.format(
name=type(self).__name__,
content=self.__dict__,
row=self.row,
col=self.col,
code=self.code,
)

def __hash__(self):
return hash((self.row, self.col, self.code))
2 changes: 2 additions & 0 deletions deal/linter/_extractors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .common import get_name
from .contracts import get_contracts
from .exceptions import get_exceptions
from .exceptions_stubs import get_exceptions_stubs
from .globals import get_globals
from .imports import get_imports
from .prints import get_prints
Expand All @@ -11,6 +12,7 @@
__all__ = [
'get_contracts',
'get_exceptions',
'get_exceptions_stubs',
'get_globals',
'get_imports',
'get_name',
Expand Down
25 changes: 18 additions & 7 deletions deal/linter/_extractors/common.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# built-in
import ast
from contextlib import suppress
from types import SimpleNamespace
from typing import Optional
from typing import Iterator, List, NamedTuple, Optional, Tuple

# external
import astroid
Expand All @@ -27,15 +28,15 @@
)


class Token:
def __init__(self, value, line: int, col: int):
self.value = value
self.line = line
self.col = col
class Token(NamedTuple):
value: object
line: int
col: int


def traverse(body):
def traverse(body: List) -> Iterator:
for expr in body:
# breaking apart
if isinstance(expr, TOKENS.EXPR):
yield expr.value
continue
Expand All @@ -49,8 +50,12 @@ def traverse(body):
if hasattr(expr, 'finalbody'):
yield from traverse(body=expr.finalbody)
continue

# extracting things
if isinstance(expr, TOKENS.WITH):
yield from traverse(body=expr.body)
if isinstance(expr, TOKENS.RETURN):
yield expr.value
yield expr


Expand All @@ -72,3 +77,9 @@ def get_name(expr) -> Optional[str]:
return left + '.' + expr.attr

return None


def infer(expr) -> Tuple:
with suppress(astroid.exceptions.InferenceError, RecursionError):
return tuple(g for g in expr.infer() if type(g) is not astroid.Uninferable)
return tuple()
4 changes: 2 additions & 2 deletions deal/linter/_extractors/contracts.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# built-in
from typing import Iterator, Tuple
from typing import Iterator, List, Tuple

# external
import astroid
Expand All @@ -12,7 +12,7 @@
SUPPORTED_MARKERS = {'deal.silent', 'deal.pure'}


def get_contracts(decorators: list) -> Iterator[Tuple[str, list]]:
def get_contracts(decorators: List) -> Iterator[Tuple[str, list]]:
for contract in decorators:
if isinstance(contract, TOKENS.ATTR):
name = get_name(contract)
Expand Down

0 comments on commit 91c5ba0

Please sign in to comment.