From 5b23c655e25d3bbef47955053af8d88b34e24666 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 6 Sep 2018 18:28:33 +0300 Subject: [PATCH] Version 0.0.9 release --- CHANGELOG.md | 16 ++++++ pyproject.toml | 2 +- tests/conftest.py | 15 ++++- .../{complexity => config}/wrong_arguments.py | 0 .../{complexity => config}/wrong_branches.py | 0 .../wrong_expressions.py | 0 .../{complexity => config}/wrong_returns.py | 0 .../{complexity => config}/wrong_variables.py | 0 tests/fixtures/wrong_variable.py | 56 ------------------- tests/test_checkers/test_config.py | 6 +- tests/test_checkers/test_high_complexity.py | 48 +++------------- tests/test_checkers/test_wrong_variable.py | 19 ------- .../test_function/test_expressions.py | 48 ++++++++++++++++ .../test_function/test_returns.py | 49 ++++++++++++++++ wemake_python_styleguide/types.py | 7 ++- .../visitors/wrong_name.py | 2 +- 16 files changed, 141 insertions(+), 127 deletions(-) rename tests/fixtures/{complexity => config}/wrong_arguments.py (100%) rename tests/fixtures/{complexity => config}/wrong_branches.py (100%) rename tests/fixtures/{complexity => config}/wrong_expressions.py (100%) rename tests/fixtures/{complexity => config}/wrong_returns.py (100%) rename tests/fixtures/{complexity => config}/wrong_variables.py (100%) delete mode 100644 tests/fixtures/wrong_variable.py delete mode 100644 tests/test_checkers/test_wrong_variable.py create mode 100644 tests/test_visitors/test_complexity/test_function/test_expressions.py create mode 100644 tests/test_visitors/test_complexity/test_function/test_returns.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d68792b0b..b18720d00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,22 @@ We follow Semantic Versions since the `0.1.0` release. +## Version 0.0.9 + +This is just a supporting release. +There are no new features introduced. + +### Bugfixes + +- Fixes `Attribute has no 'id'` error +- Fixes `missing 'typing_extension'` error + +### Misc + +- Errors are now tested +- Complexity tests are refactored + + ## Version 0.0.8 aka The Complex Complexity ### Features diff --git a/pyproject.toml b/pyproject.toml index 34c87d769..903f5237d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wemake-python-styleguide" -version = "0.0.8" +version = "0.0.9" description = "Opinionated styleguide that we use in wemake.services" license = "MIT" diff --git a/tests/conftest.py b/tests/conftest.py index f43ae3e9d..cb4f4d9dc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -21,9 +21,18 @@ def _is_error_class(cls) -> bool: @pytest.fixture(scope='session') def all_errors(): """Loads all errors from the package.""" - return list( # TODO: fix errors' checks - map(itemgetter(1), inspect.getmembers(errors, _is_error_class)), - ) + modules = [ + errors.imports, + errors.general, + errors.classes, + errors.complexity, + ] + + classes = [] + for module in modules: + classes.extend(inspect.getmembers(module, _is_error_class)) + + return list(map(itemgetter(1), classes)) @pytest.fixture(scope='session') diff --git a/tests/fixtures/complexity/wrong_arguments.py b/tests/fixtures/config/wrong_arguments.py similarity index 100% rename from tests/fixtures/complexity/wrong_arguments.py rename to tests/fixtures/config/wrong_arguments.py diff --git a/tests/fixtures/complexity/wrong_branches.py b/tests/fixtures/config/wrong_branches.py similarity index 100% rename from tests/fixtures/complexity/wrong_branches.py rename to tests/fixtures/config/wrong_branches.py diff --git a/tests/fixtures/complexity/wrong_expressions.py b/tests/fixtures/config/wrong_expressions.py similarity index 100% rename from tests/fixtures/complexity/wrong_expressions.py rename to tests/fixtures/config/wrong_expressions.py diff --git a/tests/fixtures/complexity/wrong_returns.py b/tests/fixtures/config/wrong_returns.py similarity index 100% rename from tests/fixtures/complexity/wrong_returns.py rename to tests/fixtures/config/wrong_returns.py diff --git a/tests/fixtures/complexity/wrong_variables.py b/tests/fixtures/config/wrong_variables.py similarity index 100% rename from tests/fixtures/complexity/wrong_variables.py rename to tests/fixtures/config/wrong_variables.py diff --git a/tests/fixtures/wrong_variable.py b/tests/fixtures/wrong_variable.py deleted file mode 100644 index 08fda36a8..000000000 --- a/tests/fixtures/wrong_variable.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -This file contains all broken variable names. -""" -_data = 1 -_result = 1 -__author__ = 'John Doe' # error here - -x = 1 # error here - - -def fixture(): - __author__ = 'John Doe' # no error, because not module metadata - - -def check_function_args(data, t, *a, **vals): # 4 errors here - result = data + t # error here for `result` - return result - - -with open('missing.txt') as f: # error here - contents = f.read() # error here - print(contents) - - -for item in range(1, 3): # error here - continue - - -for _ in range(1, 3): # should not raise error here - continue - - -try: - 1 / 0 -except ZeroDivisionError as e: # TODO: error here - pass - - -class Fixture(object): - data = 'data' # error here - result: int # error here - - def __init__(self, value): # error here - self.var = value # error here only for `var`, not for `value` - self.x = value # error here only for `x`, not for `value` - self.__private = value # error here for `__private`, not for `value` - - -val = Fixture() # error here -print(val.var) # no error here -print(val.x) # no error here - -if val: - __author__ = 'John' # no error here since it's a rare use of module meta diff --git a/tests/test_checkers/test_config.py b/tests/test_checkers/test_config.py index 363e2b950..311af256c 100644 --- a/tests/test_checkers/test_config.py +++ b/tests/test_checkers/test_config.py @@ -6,11 +6,7 @@ @pytest.mark.parametrize('filename, option_flag, option_value, error_code', [ - ('wrong_variables.py', '--max-local-variables', '100', b'Z150'), ('wrong_arguments.py', '--max-arguments', '100', b'Z151'), - ('wrong_returns.py', '--max-returns', '100', b'Z153'), - ('wrong_expressions.py', '--max-expressions', '100', b'Z154'), - ('wrong_variables.py', '--min-variable-length', '0', b'Z115'), ]) def test_max_variables_cli_option( absolute_path, @@ -20,7 +16,7 @@ def test_max_variables_cli_option( error_code, ): """Test to check that cli options work.""" - fixture = absolute_path('fixtures', 'complexity', filename) + fixture = absolute_path('fixtures', 'config', filename) process = subprocess.Popen( ['flake8', fixture, option_flag, option_value], stdout=subprocess.PIPE, diff --git a/tests/test_checkers/test_high_complexity.py b/tests/test_checkers/test_high_complexity.py index b4e8d01d4..7f2a881db 100644 --- a/tests/test_checkers/test_high_complexity.py +++ b/tests/test_checkers/test_high_complexity.py @@ -3,35 +3,16 @@ import subprocess -def test_too_many_variables_in_fixture(absolute_path): - """End-to-End test to check variables count.""" - filename = absolute_path('fixtures', 'complexity', 'wrong_variables.py') - process = subprocess.Popen( - ['flake8', '--select', 'Z', filename], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - stdout, _ = process.communicate() - - assert stdout.count(b'Z202') == 2 - - def test_too_many_arguments_in_fixture(absolute_path): - """End-to-End test to check arguments count.""" - filename = absolute_path('fixtures', 'complexity', 'wrong_arguments.py') - process = subprocess.Popen( - ['flake8', '--select', 'Z', filename], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - stdout, _ = process.communicate() - - assert stdout.count(b'Z203') == 4 + """ + End-to-End test to check arguments count. + It is required due to how 'function_type' parameter + works inside 'flake8'. -def test_too_many_returns_in_fixture(absolute_path): - """End-to-End test to check returns count.""" - filename = absolute_path('fixtures', 'complexity', 'wrong_returns.py') + Otherwise it is not set, unit tests can not cover `is_method` correctly. + """ + filename = absolute_path('fixtures', 'config', 'wrong_arguments.py') process = subprocess.Popen( ['flake8', '--select', 'Z', filename], stdout=subprocess.PIPE, @@ -39,17 +20,4 @@ def test_too_many_returns_in_fixture(absolute_path): ) stdout, _ = process.communicate() - assert stdout.count(b'Z205') == 1 - - -def test_too_many_expressions_in_fixture(absolute_path): - """End-to-End test to check expressions count.""" - filename = absolute_path('fixtures', 'complexity', 'wrong_expressions.py') - process = subprocess.Popen( - ['flake8', '--select', 'Z', filename], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - stdout, _ = process.communicate() - - assert stdout.count(b'Z206') == 1 + assert stdout.count(b'Z203') == 4 diff --git a/tests/test_checkers/test_wrong_variable.py b/tests/test_checkers/test_wrong_variable.py deleted file mode 100644 index cd80add1a..000000000 --- a/tests/test_checkers/test_wrong_variable.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- - -import subprocess - - -def test_wrong_variables_in_fixture(absolute_path): - """End-to-End test to check variable rules.""" - filename = absolute_path('fixtures', 'wrong_variable.py') - process = subprocess.Popen( - ['flake8', '--select', 'Z', filename], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - stdout, _ = process.communicate() - - assert stdout.count(b'Z114') == 12 - assert stdout.count(b'Z115') == 6 - assert stdout.count(b'Z116') == 1 - assert stdout.count(b'Z117') == 1 diff --git a/tests/test_visitors/test_complexity/test_function/test_expressions.py b/tests/test_visitors/test_complexity/test_function/test_expressions.py new file mode 100644 index 000000000..bea92a5d2 --- /dev/null +++ b/tests/test_visitors/test_complexity/test_function/test_expressions.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +import pytest + +from wemake_python_styleguide.visitors.complexity.function import ( + FunctionComplexityVisitor, + TooManyExpressionsViolation, +) + +function_without_expressions = """ +def function(): ... +""" + +function_with_expressions = """ +def function(): + print(12) + print(12 / 1) +""" + + +@pytest.mark.parametrize('code', [ + function_without_expressions, + function_with_expressions, +]) +def test_expressions_correct_count( + assert_errors, parse_ast_tree, code, default_options, +): + """Testing that expressions counted correctly.""" + tree = parse_ast_tree(code) + + visiter = FunctionComplexityVisitor(default_options) + visiter.visit(tree) + + assert_errors(visiter, []) + + +@pytest.mark.parametrize('code', [ + function_with_expressions, +]) +def test_expressions_wrong_count(assert_errors, parse_ast_tree, options, code): + """Testing that many expressions raises a warning.""" + tree = parse_ast_tree(code) + + option_values = options(max_expressions=1) + visiter = FunctionComplexityVisitor(option_values) + visiter.visit(tree) + + assert_errors(visiter, [TooManyExpressionsViolation]) diff --git a/tests/test_visitors/test_complexity/test_function/test_returns.py b/tests/test_visitors/test_complexity/test_function/test_returns.py new file mode 100644 index 000000000..55b2bc624 --- /dev/null +++ b/tests/test_visitors/test_complexity/test_function/test_returns.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +import pytest + +from wemake_python_styleguide.visitors.complexity.function import ( + FunctionComplexityVisitor, + TooManyReturnsViolation, +) + +function_without_returns = """ +def function(): ... +""" + +function_with_returns = """ +def function(): + if 1 > 2: + return 1 + return 0 +""" + + +@pytest.mark.parametrize('code', [ + function_without_returns, + function_with_returns, +]) +def test_returns_correct_count( + assert_errors, parse_ast_tree, code, default_options, +): + """Testing that returns counted correctly.""" + tree = parse_ast_tree(code) + + visiter = FunctionComplexityVisitor(default_options) + visiter.visit(tree) + + assert_errors(visiter, []) + + +@pytest.mark.parametrize('code', [ + function_with_returns, +]) +def test_returns_wrong_count(assert_errors, parse_ast_tree, options, code): + """Testing that many returns raises a warning.""" + tree = parse_ast_tree(code) + + option_values = options(max_returns=1) + visiter = FunctionComplexityVisitor(option_values) + visiter.visit(tree) + + assert_errors(visiter, [TooManyReturnsViolation]) diff --git a/wemake_python_styleguide/types.py b/wemake_python_styleguide/types.py index 86816bfb6..d195342cb 100644 --- a/wemake_python_styleguide/types.py +++ b/wemake_python_styleguide/types.py @@ -9,11 +9,14 @@ import ast from typing import TYPE_CHECKING, Sequence, Tuple, Type, Union -from typing_extensions import Protocol - if TYPE_CHECKING: # pragma: no cover + from typing_extensions import Protocol # noqa: Z101 + # This solves cycle imports problem: from .visitors.base import visitor # noqa: Z100,Z101,F401 +else: + # We do not need to do anything if typechecker is not working: + Protocol = object #: Visitors container, that has all enable visitors' classes: VisitorSequence = Sequence[Type['visitor.BaseNodeVisitor']] diff --git a/wemake_python_styleguide/visitors/wrong_name.py b/wemake_python_styleguide/visitors/wrong_name.py index 67812d3cc..e201d8aa3 100644 --- a/wemake_python_styleguide/visitors/wrong_name.py +++ b/wemake_python_styleguide/visitors/wrong_name.py @@ -143,7 +143,7 @@ def _check_metadata(self, node: ast.Assign): return for target_node in node.targets: - target_node_id = getattr(target_node, 'id') + target_node_id = getattr(target_node, 'id', None) if target_node_id in BAD_MODULE_METADATA_VARIABLES: self.add_error( WrongModuleMetadataViolation(node, text=target_node_id),