Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
41eddcd
Added param and params to whitelist
GirZ0n Mar 14, 2021
d176f77
Fixed flake8-spellcheck issue
GirZ0n Mar 14, 2021
1f77c30
Added new test
GirZ0n Mar 16, 2021
79f229b
Added wps-light support
GirZ0n Mar 21, 2021
3e00358
Fixed tests
GirZ0n Mar 21, 2021
fc32b5f
Merge branch 'develop' into wps-light-support
GirZ0n Mar 21, 2021
c295334
Update build.yml
GirZ0n Mar 21, 2021
5c9c329
Small test fix
GirZ0n Mar 21, 2021
542068e
Small code refactoring:
GirZ0n Mar 22, 2021
aa3a6e7
Added support for flake8-broken-line
GirZ0n Mar 23, 2021
f8c2a87
Code refactoring
GirZ0n Mar 23, 2021
48ef2af
Added support for flake8-string-format
GirZ0n Mar 26, 2021
d142938
Added tests for flake8-string-format
GirZ0n Mar 26, 2021
cff0776
Added support for flake8-commas
GirZ0n Mar 27, 2021
a5a6c82
Added tests for flake8-commas
GirZ0n Mar 27, 2021
0c88f53
Added multiline
GirZ0n Mar 27, 2021
323f748
Added C812 to ignore
GirZ0n Mar 27, 2021
4287cf0
Added support for cohesion
GirZ0n Mar 29, 2021
afaf0dd
Fixed tests
GirZ0n Mar 29, 2021
4b2930c
Merge remote-tracking branch 'origin/new-flake8-plugins' into new-fla…
GirZ0n Mar 29, 2021
7b79c6b
Added H601 (cohesion) to ignore
GirZ0n Mar 29, 2021
0d2a9cb
Added test for cohesion
GirZ0n Mar 30, 2021
923c18a
Added sqrt
GirZ0n Mar 30, 2021
9c8de68
Moved WPS_RANGE_TO_ISSUE_TYPE into CODE_PREFIX_TO_ISSUE_TYPE.
GirZ0n Apr 3, 2021
39e0443
Fixed line break after a binary operator
GirZ0n Apr 3, 2021
4988ebc
Add W503 to ignore
GirZ0n Apr 3, 2021
b21b900
Merge branch 'wps-light-support' into new-flake8-plugins
GirZ0n Apr 3, 2021
0c8d6f2
Merge branch 'develop' into new-flake8-plugins
GirZ0n Apr 3, 2021
9f05de7
Add file_name into output multiline string
GirZ0n Apr 3, 2021
97c6f66
Add file_name into output multiline fstring
GirZ0n Apr 3, 2021
346d3c9
Fixed bug
GirZ0n Apr 4, 2021
3e4ac30
Added good value to config
GirZ0n Apr 4, 2021
6076e57
Added TODO
GirZ0n Apr 5, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --exclude=.git,__pycache__,docs/source/conf.py,old,build,dist,venv,test/resources,.eggs,review.egg-info,.pytest_cache,node_modules
# TODO: change max-complexity into 10 after refactoring
flake8 . --count --max-complexity=11 --max-line-length=120 --max-doc-length=120 --ignore=I201,I202,I101,I100,R504,A003,E800,SC200,SC100,E402,W503,WPS --statistics --exclude=.git,__pycache__,docs/source/conf.py,old,build,dist,venv,test/resources,.eggs,review.egg-info,.pytest_cache,node_modules
flake8 . --count --max-complexity=11 --max-line-length=120 --max-doc-length=120 --ignore=I201,I202,I101,I100,R504,A003,E800,SC200,SC100,E402,W503,WPS,C812,H601 --statistics --exclude=.git,__pycache__,docs/source/conf.py,old,build,dist,venv,test/resources,.eggs,review.egg-info,.pytest_cache,node_modules
- name: Set up Eslint
run: |
npm install eslint --save-dev
Expand Down
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ flake8-spellcheck==0.14.0
mccabe==0.6.1
pep8-naming==0.11.1
wps-light==0.15.2
flake8-broken-line==0.3.0
flake8-string-format==0.3.0
flake8-commas==2.0.0
cohesion==1.0.0

# extra libraries and frameworks
django==3.0.8
Expand Down
11 changes: 11 additions & 0 deletions src/python/review/inspectors/flake8/.flake8
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,14 @@ ignore=W291, # trailing whitespaces
WPS527, # Require tuples as arguments for frozenset.
# WPS: OOP
WPS602, # Forbid @staticmethod decorator.
# flake8-string-format
P101, # format string does contain unindexed parameters
P102, # docstring does contain unindexed parameters
P103, # other string does contain unindexed parameters
F522, # unused named arguments. TODO: Collision with "P302"
F523, # unused positional arguments. TODO: Collision with "P301"
F524, # missing argument. TODO: Collision with "P201" and "P202"
F525, # mixing automatic and manual numbering. TODO: Collision with "P205"
# flake8-commas
C814, # missing trailing comma in Python

41 changes: 34 additions & 7 deletions src/python/review/inspectors/flake8/flake8.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import math
import re
from pathlib import Path
from typing import List
Expand All @@ -7,7 +8,14 @@
from src.python.review.inspectors.base_inspector import BaseInspector
from src.python.review.inspectors.flake8.issue_types import CODE_PREFIX_TO_ISSUE_TYPE, CODE_TO_ISSUE_TYPE
from src.python.review.inspectors.inspector_type import InspectorType
from src.python.review.inspectors.issue import BaseIssue, CodeIssue, CyclomaticComplexityIssue, IssueType, IssueData
from src.python.review.inspectors.issue import (
BaseIssue,
CodeIssue,
CyclomaticComplexityIssue,
IssueType,
IssueData,
CohesionIssue,
)
from src.python.review.inspectors.tips import get_cyclomatic_complexity_tip

logger = logging.getLogger(__name__)
Expand All @@ -27,6 +35,7 @@ def inspect(cls, path: Path, config: dict) -> List[BaseIssue]:
f'--format={FORMAT}',
f'--config={PATH_FLAKE8_CONFIG}',
'--max-complexity', '0',
'--cohesion-below', '100',
path,
]
output = run_in_subprocess(command)
Expand All @@ -36,12 +45,14 @@ def inspect(cls, path: Path, config: dict) -> List[BaseIssue]:
def parse(cls, output: str) -> List[BaseIssue]:
row_re = re.compile(r'^(.*):(\d+):(\d+):([A-Z]+\d{3}):(.*)$', re.M)
cc_description_re = re.compile(r"'(.+)' is too complex \((\d+)\)")
cohesion_description_re = re.compile(r"class has low \((\d*\.?\d*)%\) cohesion")

issues: List[BaseIssue] = []
for groups in row_re.findall(output):
description = groups[4]
origin_class = groups[3]
cc_match = cc_description_re.match(description)
cohesion_match = cohesion_description_re.match(description)
file_path = Path(groups[0])
line_no = int(groups[1])

Expand All @@ -51,15 +62,20 @@ def parse(cls, output: str) -> List[BaseIssue]:
line_number=line_no,
column_number=column_number,
origin_class=origin_class)
if cc_match is not None:
issue_data['description'] = get_cyclomatic_complexity_tip()
issue_data['cc_value'] = int(cc_match.groups()[1])
issue_data['type'] = IssueType.CYCLOMATIC_COMPLEXITY
if cc_match is not None: # mccabe: cyclomatic complexity
issue_data[IssueData.DESCRIPTION.value] = get_cyclomatic_complexity_tip()
issue_data[IssueData.CYCLOMATIC_COMPLEXITY.value] = int(cc_match.groups()[1])
issue_data[IssueData.ISSUE_TYPE.value] = IssueType.CYCLOMATIC_COMPLEXITY
issues.append(CyclomaticComplexityIssue(**issue_data))
elif cohesion_match is not None: # flake8-cohesion
issue_data[IssueData.DESCRIPTION.value] = description # TODO: Add tip
issue_data[IssueData.COHESION_LACK.value] = cls.__get_cohesion_lack(float(cohesion_match.group(1)))
issue_data[IssueData.ISSUE_TYPE.value] = IssueType.COHESION
issues.append(CohesionIssue(**issue_data))
else:
issue_type = cls.choose_issue_type(origin_class)
issue_data['type'] = issue_type
issue_data['description'] = description
issue_data[IssueData.ISSUE_TYPE.value] = issue_type
issue_data[IssueData.DESCRIPTION.value] = description
issues.append(CodeIssue(**issue_data))

return issues
Expand All @@ -82,3 +98,14 @@ def choose_issue_type(code: str) -> IssueType:
return IssueType.BEST_PRACTICES

return issue_type

@staticmethod
def __get_cohesion_lack(cohesion_percentage: float) -> int:
"""
Converts cohesion percentage to lack of cohesion.
Calculated by the formula: floor(100 - cohesion_percentage).

:param cohesion_percentage: cohesion set as a percentage.
:return: lack of cohesion
"""
return math.floor(100 - cohesion_percentage)
12 changes: 12 additions & 0 deletions src/python/review/inspectors/flake8/issue_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@
# builtin naming
'A003': IssueType.BEST_PRACTICES,

# flake8-broken-line
'N400': IssueType.CODE_STYLE,

# flake8-commas
"C812": IssueType.CODE_STYLE,
"C813": IssueType.CODE_STYLE,
"C815": IssueType.CODE_STYLE,
"C816": IssueType.CODE_STYLE,
"C818": IssueType.CODE_STYLE,
"C819": IssueType.CODE_STYLE,

# WPS: Naming
"WPS117": IssueType.CODE_STYLE, # Forbid naming variables self, cls, or mcs.
"WPS125": IssueType.ERROR_PRONE, # Forbid variable or module names which shadow builtin names.
Expand Down Expand Up @@ -87,6 +98,7 @@
'B': IssueType.ERROR_PRONE, # flake8-bugbear
'A': IssueType.ERROR_PRONE, # flake8-builtins
'R': IssueType.ERROR_PRONE, # flake8-return
'P': IssueType.ERROR_PRONE, # flake8-format-string

'E': IssueType.CODE_STYLE, # standard flake8
'W': IssueType.CODE_STYLE, # standard flake8
Expand Down
22 changes: 14 additions & 8 deletions src/python/review/inspectors/intellij/issue_types/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
from typing import Dict

from src.python.review import IssueType
from .java import ISSUE_CLASS_TO_ISSUE_TYPE as \
JAVA_ISSUE_CLASS_TO_ISSUE_TYPE
from .kotlin import ISSUE_CLASS_TO_ISSUE_TYPE as \
KOTLIN_ISSUE_CLASS_TO_ISSUE_TYPE
from .python import ISSUE_CLASS_TO_ISSUE_TYPE as \
PYTHON_ISSUE_CLASS_TO_ISSUE_TYPE
from src.python.review.inspectors.issue import IssueType

from src.python.review.inspectors.intellij.issue_types.java import (
ISSUE_CLASS_TO_ISSUE_TYPE as JAVA_ISSUE_CLASS_TO_ISSUE_TYPE,
)

from src.python.review.inspectors.intellij.issue_types.kotlin import (
ISSUE_CLASS_TO_ISSUE_TYPE as KOTLIN_ISSUE_CLASS_TO_ISSUE_TYPE,
)

from src.python.review.inspectors.intellij.issue_types.python import (
ISSUE_CLASS_TO_ISSUE_TYPE as PYTHON_ISSUE_CLASS_TO_ISSUE_TYPE,
)

ISSUE_CLASS_TO_ISSUE_TYPE: Dict[str, IssueType] = {
**JAVA_ISSUE_CLASS_TO_ISSUE_TYPE,
**PYTHON_ISSUE_CLASS_TO_ISSUE_TYPE,
**KOTLIN_ISSUE_CLASS_TO_ISSUE_TYPE
**KOTLIN_ISSUE_CLASS_TO_ISSUE_TYPE,
}
1 change: 1 addition & 0 deletions src/python/review/inspectors/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class IssueData(Enum):
FUNCTION_LEN = 'func_len'
BOOL_EXPR_LEN = 'bool_expr_len'
CYCLOMATIC_COMPLEXITY = 'cc_value'
COHESION_LACK = 'cohesion_lack'

@classmethod
def get_base_issue_data_dict(cls,
Expand Down
22 changes: 18 additions & 4 deletions src/python/review/inspectors/parsers/checkstyle_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,24 @@

from src.python.review.common.file_system import get_content_from_file
from src.python.review.inspectors.inspector_type import InspectorType
from src.python.review.inspectors.issue import BaseIssue, BoolExprLenIssue, CodeIssue, CyclomaticComplexityIssue, \
FuncLenIssue, IssueType, LineLenIssue, IssueData
from src.python.review.inspectors.tips import get_bool_expr_len_tip, get_cyclomatic_complexity_tip, get_func_len_tip, \
get_line_len_tip

from src.python.review.inspectors.issue import (
BaseIssue,
BoolExprLenIssue,
CodeIssue,
CyclomaticComplexityIssue,
FuncLenIssue,
IssueType,
LineLenIssue,
IssueData,
)

from src.python.review.inspectors.tips import (
get_bool_expr_len_tip,
get_cyclomatic_complexity_tip,
get_func_len_tip,
get_line_len_tip,
)

logger = logging.getLogger(__name__)

Expand Down
29 changes: 24 additions & 5 deletions src/python/review/inspectors/springlint/springlint.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,30 @@
from src.python.review.common.subprocess_runner import run_in_subprocess
from src.python.review.inspectors.base_inspector import BaseInspector
from src.python.review.inspectors.inspector_type import InspectorType
from src.python.review.inspectors.issue import BaseIssue, ChildrenNumberIssue, ClassResponseIssue, CodeIssue, \
CohesionIssue, \
CouplingIssue, InheritanceIssue, IssueType, MethodNumberIssue, WeightedMethodIssue, IssueData
from src.python.review.inspectors.tips import get_child_number_tip, get_class_coupling_tip, get_class_response_tip, \
get_cohesion_tip, get_inheritance_depth_tip, get_method_number_tip, get_weighted_method_tip

from src.python.review.inspectors.issue import (
BaseIssue,
ChildrenNumberIssue,
ClassResponseIssue,
CodeIssue,
CohesionIssue,
CouplingIssue,
InheritanceIssue,
IssueType,
MethodNumberIssue,
WeightedMethodIssue,
IssueData,
)

from src.python.review.inspectors.tips import (
get_child_number_tip,
get_class_coupling_tip,
get_class_response_tip,
get_cohesion_tip,
get_inheritance_depth_tip,
get_method_number_tip,
get_weighted_method_tip,
)

PATH_TOOLS_SPRINGLINT_FILES = Path(__file__).parent / 'files'
PATH_SPRINGLINT_JAR = PATH_TOOLS_SPRINGLINT_FILES / 'springlint-0.6.jar'
Expand Down
66 changes: 42 additions & 24 deletions src/python/review/inspectors/tips.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
def get_bool_expr_len_tip() -> str:
return 'Too long boolean expression. ' \
'Try to split it into smaller expressions.'
return (
'Too long boolean expression. '
'Try to split it into smaller expressions.'
)


def get_func_len_tip() -> str:
return 'Too long function. ' \
'Try to split it into smaller functions / methods.' \
'It will make your code easy to understand and less error prone.'
return (
'Too long function. '
'Try to split it into smaller functions / methods. '
'It will make your code easy to understand and less error prone.'
)


def get_line_len_tip() -> str:
return 'Too long line. ' \
'Try to split it into smaller lines.' \
'It will make your code easy to understand.'
return (
'Too long line. '
'Try to split it into smaller lines. '
'It will make your code easy to understand.'
)


def get_cyclomatic_complexity_tip() -> str:
return 'Too complex function. You can figure out how to simplify this code ' \
'or split it into a set of small functions / methods. ' \
'It will make your code easy to understand and less error prone.'
return (
'Too complex function. You can figure out how to simplify this code '
'or split it into a set of small functions / methods. '
'It will make your code easy to understand and less error prone.'
)


def add_complexity_tip(description: str) -> str:
Expand All @@ -31,8 +39,10 @@ def add_complexity_tip(description: str) -> str:


def get_inheritance_depth_tip() -> str:
return 'Too deep inheritance tree is complicated to understand. ' \
'Try to reduce it (maybe you should use a composition instead).'
return (
'Too deep inheritance tree is complicated to understand. '
'Try to reduce it (maybe you should use a composition instead).'
)


# This issue will not be reported at this version
Expand All @@ -41,14 +51,18 @@ def get_child_number_tip() -> str:


def get_weighted_method_tip() -> str:
return 'The number of methods and their complexity may be too hight. ' \
'It may require too much time and effort to develop and maintain the class.'
return (
'The number of methods and their complexity may be too hight. '
'It may require too much time and effort to develop and maintain the class.'
)


def get_class_coupling_tip() -> str:
return 'The class seems to depend on too many other classes. ' \
'Increased coupling increases interclass dependencies, ' \
'making the code less modular and less suitable for reuse and testing.'
return (
'The class seems to depend on too many other classes. '
'Increased coupling increases interclass dependencies, '
'making the code less modular and less suitable for reuse and testing.'
)


# This issue will not be reported at this version
Expand All @@ -57,12 +71,16 @@ def get_cohesion_tip() -> str:


def get_class_response_tip() -> str:
return 'The class have too many methods that can potentially ' \
'be executed in response to a single message received by an object of that class. ' \
'The larger the number of methods that can be invoked from a class, ' \
'the greater the complexity of the class'
return (
'The class have too many methods that can potentially '
'be executed in response to a single message received by an object of that class. '
'The larger the number of methods that can be invoked from a class, '
'the greater the complexity of the class'
)


def get_method_number_tip() -> str:
return 'The file has too many methods inside and is complicated to understand. ' \
'Consider its decomposition to smaller classes.'
return (
'The file has too many methods inside and is complicated to understand. '
'Consider its decomposition to smaller classes.'
)
Loading