-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #51 from jamescooke/command-line
Command line
- Loading branch information
Showing
26 changed files
with
776 additions
and
154 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,94 @@ | ||
Controlling flake8-aaa in-code | ||
****************************** | ||
Controlling Flake8-AAA | ||
====================== | ||
|
||
flake8-aaa can be controlled using some special comments in | ||
your test code. | ||
In code | ||
------- | ||
|
||
Flake8-AAA can be controlled using some special comments in your test code. | ||
|
||
Explicitly marking blocks | ||
========================= | ||
......................... | ||
|
||
One can set the act block explicitly using the ``# act`` comment. This is | ||
necessary when there is no assignment possible. | ||
|
||
Disabling Flake8-AAA selectively | ||
................................ | ||
|
||
When Flake8-AAA finds the ``# noqa`` comment at the end of the line that | ||
defines a test function, it will ignore it. | ||
|
||
Command line | ||
------------ | ||
|
||
Flake8-AAA has a simple command line interface to assist with development and | ||
debugging. Its goal is to show the state of analysed test functions, which | ||
lines are considered to be parts of which blocks and any errors that have been | ||
found. | ||
|
||
Invocation, output and return value | ||
................................... | ||
|
||
With Flake8-AAA installed, it can be called as a Python module:: | ||
|
||
$ python -m flake8_aaa [test_file] | ||
|
||
Where ``[test_file]`` is the path to a file to be checked. | ||
|
||
The return value of the execution is the number of errors found in the file, | ||
for example:: | ||
|
||
$ python -m flake8_aaa ../some_test.py | ||
------+------------------------------------------------------------------------ | ||
1 DEF|def test(): | ||
2 ARR| x = 1 | ||
3 ARR| y = 1 | ||
4 ACT| result = x + y | ||
^ AAA03 expected 1 blank line before Act block, found none | ||
5 BL | | ||
6 ASS| assert result == 2 | ||
------+------------------------------------------------------------------------ | ||
1 | ERROR | ||
$ echo "$?" | ||
1 | ||
|
||
And once the error above is fixed, the return value returns to zero:: | ||
|
||
$ python -m flake8_aaa ../some_test.py | ||
------+------------------------------------------------------------------------ | ||
1 DEF|def test(): | ||
2 ARR| x = 1 | ||
3 ARR| y = 1 | ||
4 BL | | ||
5 ACT| result = x + y | ||
6 BL | | ||
7 ASS| assert result == 2 | ||
------+------------------------------------------------------------------------ | ||
0 | ERRORS | ||
$ echo "$?" | ||
0 | ||
|
||
Line markers | ||
............ | ||
|
||
Each test found in the passed file is displayed. Each line is annotated with | ||
its line number in the file and a marker to show how Flake8-AAA classified that | ||
line. Line markers are as follows: | ||
|
||
ACT | ||
Line is part of the Act Block. | ||
|
||
One can set the act block explicitly using the ``# act`` | ||
comment. This is necessary when there is no assignment | ||
possible. | ||
ARR | ||
Line is part of an Arrange Block. | ||
|
||
Disabling flake8-aaa selectively | ||
================================ | ||
ASS | ||
Line is part of the Assert Block. | ||
|
||
When flake8-aaa finds the ``# noqa`` comment after the | ||
function/method head it will ignore this function/method. | ||
BL | ||
Line is considered a blank line for layout purposes. | ||
|
||
DEF | ||
Test function definition. | ||
|
||
??? | ||
Unprocessed line. Flake8-AAA has not categorised this line. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Dirty hack to allow for direct running of flake8-aaa from the command line, | ||
# bypassing flake8's harness. Goal of this is to allow for debugging of | ||
# analysis, especially around how flake8-aaa has assigned lines of code to | ||
# particular blocks. | ||
|
||
import argparse | ||
import sys | ||
|
||
from .command_line import do_command_line | ||
|
||
|
||
def main() -> int: | ||
parser = argparse.ArgumentParser(description='flake8-aaa command line debug') | ||
parser.add_argument('infile', type=argparse.FileType('r'), help='File to be linted') | ||
args = parser.parse_args() | ||
return do_command_line(args.infile) | ||
|
||
|
||
if __name__ == '__main__': | ||
sys.exit(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,74 @@ | ||
import ast | ||
from typing import List, Type, TypeVar | ||
|
||
from .helpers import node_is_pytest_raises, node_is_result_assignment, node_is_unittest_raises | ||
from .types import ActBlockType | ||
from .types import ActBlockType, LineType | ||
|
||
AB = TypeVar('AB', bound='ActBlock') # Place holder for ActBlock instances | ||
|
||
class ActBlock(object): | ||
|
||
class ActBlock: | ||
""" | ||
Attributes: | ||
node | ||
block_type (ActBlockType) | ||
""" | ||
|
||
def __init__(self, node, block_type): | ||
def __init__(self, node: ast.AST, block_type: ActBlockType) -> None: | ||
""" | ||
Args: | ||
node | ||
block_type (ActBlockType) | ||
""" | ||
self.node = node | ||
self.block_type = block_type | ||
self.node = node # type: ast.AST | ||
self.block_type = block_type # type: ActBlockType | ||
|
||
@classmethod | ||
def build_body(cls, body): | ||
def build_body(cls: Type[AB], body: List[ast.stmt]): | ||
""" | ||
Args: | ||
body (list (ast.node)): List of nodes from a block. | ||
Returns: | ||
list (ActBlock) | ||
Note: | ||
Return type is probably ``-> List[AB]``, but can't get it to pass. | ||
""" | ||
act_blocks = [] | ||
act_blocks = [] # type: List[ActBlock] | ||
for child_node in body: | ||
act_blocks += ActBlock.build(child_node) | ||
return act_blocks | ||
|
||
@classmethod | ||
def build(cls, node): | ||
""" | ||
Args: | ||
node (ast.node): A node, decorated with ``ASTTokens``. | ||
Returns: | ||
list(ActBlock) | ||
""" | ||
def build(cls: Type[AB], node: ast.AST) -> List[AB]: | ||
if node_is_result_assignment(node): | ||
return [cls(node, ActBlockType.result_assignment)] | ||
elif node_is_pytest_raises(node): | ||
if node_is_pytest_raises(node): | ||
return [cls(node, ActBlockType.pytest_raises)] | ||
elif node_is_unittest_raises(node): | ||
if node_is_unittest_raises(node): | ||
return [cls(node, ActBlockType.unittest_raises)] | ||
|
||
token = node.first_token # type: ignore | ||
# Check if line marked with '# act' | ||
if node.first_token.line.strip().endswith('# act'): | ||
if token.line.strip().endswith('# act'): | ||
return [cls(node, ActBlockType.marked_act)] | ||
|
||
# Recurse if it's a context manager | ||
if isinstance(node, ast.With): | ||
return cls.build_body(node.body) | ||
|
||
return [] | ||
|
||
def mark_line_types(self, line_types: List[LineType], first_line_no: int) -> List[LineType]: | ||
""" | ||
Marks the lines occupied by this ActBlock. | ||
Note: | ||
Mutates the ``line_types`` list. | ||
Raises: | ||
AssertionError: When position in ``line_types`` has already been | ||
marked to something other than ``???:unprocessed``. | ||
""" | ||
# Lines calculated relative to file | ||
start_line = self.node.first_token.start[0] # type:ignore | ||
end_line = self.node.last_token.end[0] # type:ignore | ||
for file_line_no in range(start_line, end_line + 1): | ||
assert line_types[file_line_no - first_line_no] is LineType.unprocessed | ||
line_types[file_line_no - first_line_no] = LineType.act_block | ||
return line_types |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,12 @@ | ||
class AssertBlock(object): | ||
""" | ||
Attributes: | ||
nodes (list (ast Node)) | ||
""" | ||
import ast | ||
|
||
def __init__(self): | ||
self.nodes = [] | ||
from .multi_node_block import MultiNodeBlock | ||
from .types import LineType | ||
|
||
def add_node(self, node): | ||
|
||
class AssertBlock(MultiNodeBlock): | ||
line_type = LineType.assert_block | ||
|
||
def add_node(self, node: ast.AST) -> bool: | ||
self.nodes.append(node) | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import ast | ||
from typing import IO | ||
|
||
from .checker import Checker | ||
|
||
|
||
def do_command_line(infile: IO[str]) -> int: | ||
""" | ||
Currently a small stub to create an instance of Checker for the passed | ||
``infile`` and run its test functions through linting. | ||
Args: | ||
infile | ||
Returns: | ||
int: Number of flake8 errors raised. | ||
""" | ||
lines = infile.readlines() | ||
tree = ast.parse(''.join(lines)) | ||
checker = Checker(tree, lines, infile.name) | ||
checker.load() | ||
for func in checker.all_funcs(): | ||
errors = func.get_errors() | ||
print(func, end='') | ||
return len(errors) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.