Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d56dcd0
Code refactoring:
GirZ0n Aug 4, 2021
9ff00f1
get_influence_json_dict -> get_influence_on_penalty_json_dict
GirZ0n Aug 5, 2021
144b828
Fixed the old test and added a new one
GirZ0n Aug 5, 2021
d55f794
typo fix
GirZ0n Aug 5, 2021
fd71d5e
Renamed file
GirZ0n Aug 5, 2021
3cde709
Fixed quotes
GirZ0n Aug 5, 2021
012456b
Added a new test and refactored the old one
GirZ0n Aug 5, 2021
433e9fb
Added typing
GirZ0n Aug 5, 2021
820a2f0
Added group_issues_by_difficulty
GirZ0n Aug 6, 2021
db6f190
Added --group-by-difficulty flag
GirZ0n Aug 6, 2021
a5205fe
Added IssueDifficulty
GirZ0n Aug 6, 2021
578bf70
Added support for difficulty levels
GirZ0n Aug 6, 2021
23ccb13
Small fix
GirZ0n Aug 6, 2021
8ec45d8
Merge remote-tracking branch 'origin/develop' into difficulty-levels
GirZ0n Aug 6, 2021
31a6f52
Fixed tests
GirZ0n Aug 6, 2021
2628925
Added IssueDifficulty
GirZ0n Aug 6, 2021
36c1f64
Added difficulty
GirZ0n Aug 6, 2021
cc305f1
Merge remote-tracking branch 'origin/develop' into print-review-refac…
GirZ0n Aug 6, 2021
57ceb58
Merge remote-tracking branch 'origin/print-review-refactoring' into d…
GirZ0n Aug 6, 2021
ca33607
Fixed tests
GirZ0n Aug 6, 2021
bac2ae9
Fixed tests
GirZ0n Aug 6, 2021
fa0994d
Replaced literals with constants and added group_by_difficulty
GirZ0n Aug 7, 2021
3c7d6f7
Small fix
GirZ0n Aug 7, 2021
16f8e2d
Fixed test and added a new one
GirZ0n Aug 7, 2021
b497cb8
Update README.md
GirZ0n Aug 10, 2021
c1cb041
Undo Update README.md
GirZ0n Aug 10, 2021
1eebc0a
Fixed PR issues
GirZ0n Aug 10, 2021
060ea6e
Merge remote-tracking branch 'origin/print-review-refactoring' into d…
GirZ0n Aug 10, 2021
cae2932
Added tests
GirZ0n Aug 10, 2021
ae760fd
Merge remote-tracking branch 'origin/develop' into difficulty-levels
GirZ0n Aug 11, 2021
6d9ccb7
Added history
GirZ0n Aug 11, 2021
d40ba97
Added new tests and updated old ones
GirZ0n Aug 11, 2021
bff6380
Update README.md
GirZ0n Aug 11, 2021
3f7928a
Fixed flake8
GirZ0n Aug 11, 2021
7ccab26
Small fixes
GirZ0n Aug 11, 2021
90bb649
Merge remote-tracking branch 'origin/difficulty-levels' into difficul…
GirZ0n Aug 11, 2021
4abf578
Small fix
GirZ0n Aug 11, 2021
a383b6d
Small fix
GirZ0n Aug 11, 2021
40df929
Fixed flake8
GirZ0n Aug 11, 2021
9cf32f9
Small fix
GirZ0n Aug 11, 2021
0287062
Small fix
GirZ0n Aug 11, 2021
e033452
Added logger
GirZ0n Aug 13, 2021
4596a8a
Fixed todo message
GirZ0n Aug 13, 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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ Argument | Description
**‑‑new-format** | the argument determines whether the tool should use the _new format_. _New format_ means separating the result by the files to allow getting quality and observed issues for each file separately. The default value is `False`.
**‑‑history** | JSON string with a list of issues for each language. For each issue its class and quantity are specified. Example: `--history "{\"python\": [{\"origin_class\": \"SC200\", \"number\": 20}, {\"origin_class\": \"WPS314\", \"number\": 3}]}"`
**‑‑with‑all‑categories** | Without this flag, all issues will be categorized into 5 main categories: `CODE_STYLE`, `BEST_PRACTICES`, `ERROR_PRONE`, `COMPLEXITY`, `INFO`.
**‑‑group‑by‑difficulty** | With this flag, the final grade and influence on penalty will be grouped by the issue difficulty.

The output examples:

Expand All @@ -127,6 +128,7 @@ The output examples:
"line_number": 54,
"column_number": 0,
"category": "FUNC_LEN",
"difficulty": "EASY",
"influence_on_penalty": 0
},
...
Expand Down Expand Up @@ -157,6 +159,7 @@ The output examples:
"line_number": 174,
"column_number": 12,
"category": "BEST_PRACTICES",
"difficulty": "MEDIUM",
"influence_on_penalty": 0
},
...
Expand Down
3 changes: 3 additions & 0 deletions src/python/common/tool_arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class RunToolArgument(Enum):
'Without this flag, all issues will be categorized into 5 main categories: '
'CODE_STYLE, BEST_PRACTICES, ERROR_PRONE, COMPLEXITY, INFO.')

GROUP_BY_DIFFICULTY = ArgumentsInfo(None, '--group-by-difficulty',
'With this flag, the final grade will be grouped by the issue difficulty.')

SOLUTIONS_FILE_PATH = ArgumentsInfo(None, 'solutions_file_path',
'Local XLSX-file or CSV-file path. '
'Your file must include column-names: '
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
CodeIssue,
get_issue_class_by_issue_type,
IssueData,
IssueDifficulty,
IssueType,
Measurable,
MEASURABLE_ISSUE_TYPE_TO_MEASURE_NAME,
Expand All @@ -32,6 +33,7 @@ def default(self, obj):
IssueData.LINE_NUMBER.value: obj.line_no,
IssueData.COLUMN_NUMBER.value: obj.column_no,
IssueData.INSPECTOR_TYPE.value: obj.inspector_type.value,
IssueData.DIFFICULTY.value: obj.difficulty.value,
}

if isinstance(obj, Measurable):
Expand All @@ -50,6 +52,10 @@ def object_hook(self, json_dict):
json_dict[IssueData.ISSUE_TYPE.value] = IssueType(json_dict[IssueData.ISSUE_TYPE.value])
json_dict[IssueData.INSPECTOR_TYPE.value] = InspectorType(json_dict[IssueData.INSPECTOR_TYPE.value])
json_dict[IssueData.FILE_PATH.value] = Path(json_dict[IssueData.FILE_PATH.value])
# TODO: remove get after analyzing raw issue statistics
json_dict[IssueData.DIFFICULTY.value] = IssueDifficulty(
json_dict.get(IssueData.DIFFICULTY.value, IssueDifficulty.HARD.value),
)

issue_type = json_dict[IssueData.ISSUE_TYPE.value]
if issue_type in MEASURABLE_ISSUE_TYPE_TO_MEASURE_NAME.keys():
Expand Down
1 change: 1 addition & 0 deletions src/python/review/application_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class ApplicationConfig:
end_line: Optional[int] = None
new_format: bool = False
history: Optional[str] = None
group_by_difficulty: bool = False


@unique
Expand Down
3 changes: 2 additions & 1 deletion src/python/review/inspectors/checkstyle/checkstyle.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from src.python.review.inspectors.base_inspector import BaseInspector
from src.python.review.inspectors.checkstyle.issue_types import CHECK_CLASS_NAME_TO_ISSUE_TYPE
from src.python.review.inspectors.inspector_type import InspectorType
from src.python.review.inspectors.issue import BaseIssue, IssueType
from src.python.review.inspectors.issue import BaseIssue, IssueDifficulty, IssueType
from src.python.review.inspectors.parsers.checkstyle_parser import parse_checkstyle_file_result

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -51,6 +51,7 @@ def inspect(self, path: Path, config: Dict[str, Any]) -> List[BaseIssue]:
return parse_checkstyle_file_result(Path(output_path),
self.inspector_type,
self.choose_issue_type,
IssueDifficulty.get_by_issue_type,
self.origin_class_to_pattern)

@classmethod
Expand Down
3 changes: 2 additions & 1 deletion src/python/review/inspectors/detekt/detekt.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from src.python.review.inspectors.base_inspector import BaseInspector
from src.python.review.inspectors.detekt.issue_types import DETECT_CLASS_NAME_TO_ISSUE_TYPE
from src.python.review.inspectors.inspector_type import InspectorType
from src.python.review.inspectors.issue import BaseIssue, IssueType
from src.python.review.inspectors.issue import BaseIssue, IssueDifficulty, IssueType
from src.python.review.inspectors.parsers.checkstyle_parser import parse_checkstyle_file_result

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -50,6 +50,7 @@ def inspect(self, path: Path, config: Dict[str, Any]) -> List[BaseIssue]:
return parse_checkstyle_file_result(output_path,
self.inspector_type,
self.choose_issue_type,
IssueDifficulty.get_by_issue_type,
self.origin_class_to_pattern)

@classmethod
Expand Down
3 changes: 2 additions & 1 deletion src/python/review/inspectors/eslint/eslint.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from src.python.review.inspectors.base_inspector import BaseInspector
from src.python.review.inspectors.eslint.issue_types import ESLINT_CLASS_NAME_TO_ISSUE_TYPE
from src.python.review.inspectors.inspector_type import InspectorType
from src.python.review.inspectors.issue import BaseIssue, IssueType
from src.python.review.inspectors.issue import BaseIssue, IssueDifficulty, IssueType
from src.python.review.inspectors.parsers.checkstyle_parser import parse_checkstyle_file_result

PATH_ESLINT_CONFIG = Path(__file__).parent / '.eslintrc'
Expand Down Expand Up @@ -41,6 +41,7 @@ def inspect(self, path: Path, config: Dict[str, Any]) -> List[BaseIssue]:
issues = parse_checkstyle_file_result(output_path,
self.inspector_type,
self.choose_issue_type,
IssueDifficulty.get_by_issue_type,
self.origin_class_to_pattern)

output_path.unlink()
Expand Down
12 changes: 10 additions & 2 deletions src/python/review/inspectors/flake8/flake8.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
CohesionIssue,
CyclomaticComplexityIssue,
IssueData,
IssueDifficulty,
IssueType,
LineLenIssue,
)
Expand Down Expand Up @@ -71,25 +72,32 @@ def parse(cls, output: str) -> List[BaseIssue]:
column_number=column_number,
origin_class=origin_class)
if cc_match is not None: # mccabe: cyclomatic complexity
issue_type = IssueType.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
issue_data[IssueData.ISSUE_TYPE.value] = issue_type
issue_data[IssueData.DIFFICULTY.value] = IssueDifficulty.get_by_issue_type(issue_type)
issues.append(CyclomaticComplexityIssue(**issue_data))
elif cohesion_match is not None: # flake8-cohesion
issue_type = IssueType.COHESION
issue_data[IssueData.DESCRIPTION.value] = description # TODO: Add tip
issue_data[IssueData.COHESION_LACK.value] = convert_percentage_of_value_to_lack_of_value(
float(cohesion_match.group(1)),
)
issue_data[IssueData.ISSUE_TYPE.value] = IssueType.COHESION
issue_data[IssueData.ISSUE_TYPE.value] = issue_type
issue_data[IssueData.DIFFICULTY.value] = IssueDifficulty.get_by_issue_type(issue_type)
issues.append(CohesionIssue(**issue_data))
elif line_len_match is not None:
issue_type = IssueType.LINE_LEN
issue_data[IssueData.DESCRIPTION.value] = get_line_len_tip()
issue_data[IssueData.LINE_LEN.value] = int(line_len_match.groups()[0])
issue_data[IssueData.ISSUE_TYPE.value] = IssueType.LINE_LEN
issue_data[IssueData.DIFFICULTY.value] = IssueDifficulty.get_by_issue_type(issue_type)
issues.append(LineLenIssue(**issue_data))
else:
issue_type = cls.choose_issue_type(origin_class)
issue_data[IssueData.ISSUE_TYPE.value] = issue_type
issue_data[IssueData.DIFFICULTY.value] = IssueDifficulty.get_by_issue_type(issue_type)
issue_data[IssueData.DESCRIPTION.value] = description
issues.append(CodeIssue(**issue_data))

Expand Down
3 changes: 2 additions & 1 deletion src/python/review/inspectors/intellij/intellij.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from src.python.review.inspectors.base_inspector import BaseInspector
from src.python.review.inspectors.inspector_type import InspectorType
from src.python.review.inspectors.intellij.issue_types import ISSUE_CLASS_TO_ISSUE_TYPE
from src.python.review.inspectors.issue import BaseIssue, CodeIssue, IssueType
from src.python.review.inspectors.issue import BaseIssue, CodeIssue, IssueDifficulty, IssueType

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -161,6 +161,7 @@ def parse(cls, out_dir_path: Path,
origin_class=issue_class,
inspector_type=cls.inspector_type,
type=issue_type,
difficulty=IssueDifficulty.get_by_issue_type(issue_type),
))

return issues
Expand Down
47 changes: 47 additions & 0 deletions src/python/review/inspectors/issue.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import abc
import logging
from collections import defaultdict
from dataclasses import dataclass
from enum import Enum, unique
Expand All @@ -7,6 +8,8 @@

from src.python.review.inspectors.inspector_type import InspectorType

logger = logging.getLogger(__name__)


@unique
class IssueType(Enum):
Expand Down Expand Up @@ -118,6 +121,7 @@ class IssueData(Enum):
# Additional fields
ISSUE_TYPE = 'type'
DESCRIPTION = 'description'
DIFFICULTY = 'difficulty'

LINE_LEN = 'line_len'
FUNCTION_LEN = 'func_len'
Expand All @@ -142,6 +146,48 @@ def get_base_issue_data_dict(cls,
}


@unique
class IssueDifficulty(Enum):
EASY = 'EASY'
MEDIUM = 'MEDIUM'
HARD = 'HARD'

@classmethod
def get_by_issue_type(cls, issue_type: IssueType) -> 'IssueDifficulty':
issue_type_to_difficulty = {
# Easy
IssueType.CODE_STYLE: cls.EASY,
IssueType.LINE_LEN: cls.EASY,
IssueType.FUNC_LEN: cls.EASY,
IssueType.BOOL_EXPR_LEN: cls.EASY,
IssueType.INFO: cls.EASY, # Because INFO should always be shown on the platforms

# Medium
IssueType.BEST_PRACTICES: cls.MEDIUM,

# Hard
IssueType.CLASS_RESPONSE: cls.HARD,
IssueType.METHOD_NUMBER: cls.HARD,
IssueType.ERROR_PRONE: cls.HARD,
IssueType.COMPLEXITY: cls.HARD,
IssueType.CYCLOMATIC_COMPLEXITY: cls.HARD,
IssueType.INHERITANCE_DEPTH: cls.HARD,
IssueType.CHILDREN_NUMBER: cls.HARD,
IssueType.WEIGHTED_METHOD: cls.HARD,
IssueType.COUPLING: cls.HARD,
IssueType.COHESION: cls.HARD,
IssueType.MAINTAINABILITY: cls.HARD,
IssueType.UNDEFINED: cls.HARD,
IssueType.ARCHITECTURE: cls.HARD,
}

if issue_type not in issue_type_to_difficulty:
logger.warning(f'IssueDifficulty: {issue_type} - unknown issue type.')
return cls.HARD

return issue_type_to_difficulty[issue_type]


@dataclass(frozen=True, eq=True)
class ShortIssue:
origin_class: str
Expand All @@ -158,6 +204,7 @@ class BaseIssue(ShortIssue):
column_no: int

inspector_type: InspectorType
difficulty: IssueDifficulty


class Measurable(abc.ABC):
Expand Down
3 changes: 3 additions & 0 deletions src/python/review/inspectors/parsers/checkstyle_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
CyclomaticComplexityIssue,
FuncLenIssue,
IssueData,
IssueDifficulty,
IssueType,
LineLenIssue,
)
Expand Down Expand Up @@ -101,6 +102,7 @@ def parse_checkstyle_file_result(
file_path: Path,
inspector_type: InspectorType,
issue_type_selector: Callable[[str], IssueType],
difficulty_selector: Callable[[IssueType], IssueDifficulty],
origin_class_to_description: Dict[str, str]) -> List[BaseIssue]:
"""
Parses the output, which is a xml file, and returns a list of the issues found there.
Expand Down Expand Up @@ -137,6 +139,7 @@ def parse_checkstyle_file_result(

issue_type = issue_type_selector(origin_class)
issue_data[IssueData.ISSUE_TYPE.value] = issue_type
issue_data[IssueData.DIFFICULTY.value] = difficulty_selector(issue_type)

if origin_class in origin_class_to_description:
pattern = origin_class_to_description.get(origin_class)
Expand Down
3 changes: 2 additions & 1 deletion src/python/review/inspectors/pmd/pmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from src.python.review.inspectors.base_inspector import BaseInspector
from src.python.review.inspectors.common import remove_prefix
from src.python.review.inspectors.inspector_type import InspectorType
from src.python.review.inspectors.issue import BaseIssue, CodeIssue, IssueType
from src.python.review.inspectors.issue import BaseIssue, CodeIssue, IssueDifficulty, IssueType
from src.python.review.inspectors.pmd.issue_types import PMD_RULE_TO_ISSUE_TYPE

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -78,6 +78,7 @@ def parse_output(self, output_path: Path) -> List[BaseIssue]:
origin_class=row['Rule'],
description=row['Description'],
inspector_type=self.inspector_type,
difficulty=IssueDifficulty.get_by_issue_type(self.choose_issue_type(row['Rule'])),
) for row in reader]

@classmethod
Expand Down
17 changes: 13 additions & 4 deletions src/python/review/inspectors/pyast/python_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from src.python.review.common.language import Language
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, BoolExprLenIssue, FuncLenIssue, IssueType
from src.python.review.inspectors.issue import BaseIssue, BoolExprLenIssue, FuncLenIssue, IssueDifficulty, IssueType
from src.python.review.inspectors.tips import get_bool_expr_len_tip, get_func_len_tip

BOOL_EXPR_LEN_ORIGIN_CLASS = 'C001'
Expand All @@ -32,6 +32,8 @@ def visit(self, node: ast.AST):
if isinstance(inner_node, ast.BoolOp):
length += len(inner_node.values) - 1

issue_type = PythonAstInspector.choose_issue_type(BOOL_EXPR_LEN_ORIGIN_CLASS)

self.bool_expression_lens.append(BoolExprLenIssue(
file_path=self._file_path,
line_no=node.lineno,
Expand All @@ -40,7 +42,8 @@ def visit(self, node: ast.AST):
origin_class=BOOL_EXPR_LEN_ORIGIN_CLASS,
inspector_type=self._inspector_type,
bool_expr_len=length,
type=PythonAstInspector.choose_issue_type(BOOL_EXPR_LEN_ORIGIN_CLASS),
type=issue_type,
difficulty=IssueDifficulty.get_by_issue_type(issue_type),
))


Expand All @@ -61,6 +64,8 @@ def visit(self, node):
self._previous_node.lineno, node.lineno,
)

issue_type = PythonAstInspector.choose_issue_type(FUNC_LEN_ORIGIN_CLASS)

self._function_lens.append(FuncLenIssue(
file_path=self._file_path,
line_no=self._previous_node.lineno,
Expand All @@ -69,7 +74,8 @@ def visit(self, node):
origin_class=FUNC_LEN_ORIGIN_CLASS,
inspector_type=self._inspector_type,
func_len=func_length,
type=PythonAstInspector.choose_issue_type(FUNC_LEN_ORIGIN_CLASS),
type=issue_type,
difficulty=IssueDifficulty.get_by_issue_type(issue_type),
))

self._previous_node = node
Expand All @@ -83,6 +89,8 @@ def function_lens(self) -> List[FuncLenIssue]:
self._previous_node.lineno, self._n_lines + 1,
)

issue_type = PythonAstInspector.choose_issue_type(FUNC_LEN_ORIGIN_CLASS)

self._function_lens.append(FuncLenIssue(
file_path=self._file_path,
line_no=self._previous_node.lineno,
Expand All @@ -91,7 +99,8 @@ def function_lens(self) -> List[FuncLenIssue]:
origin_class=FUNC_LEN_ORIGIN_CLASS,
inspector_type=self._inspector_type,
func_len=func_length,
type=PythonAstInspector.choose_issue_type(FUNC_LEN_ORIGIN_CLASS),
type=issue_type,
difficulty=IssueDifficulty.get_by_issue_type(issue_type),
))

self._previous_node = None
Expand Down
3 changes: 2 additions & 1 deletion src/python/review/inspectors/pylint/pylint.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
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 CodeIssue, IssueType
from src.python.review.inspectors.issue import CodeIssue, IssueDifficulty, IssueType
from src.python.review.inspectors.pylint.issue_types import CATEGORY_TO_ISSUE_TYPE, CODE_TO_ISSUE_TYPE
from src.python.review.inspectors.tips import add_complexity_tip

Expand Down Expand Up @@ -71,6 +71,7 @@ def parse(cls, output: str) -> List[CodeIssue]:
description=description,
inspector_type=cls.inspector_type,
type=issue_type,
difficulty=IssueDifficulty.get_by_issue_type(issue_type),
))

return issues
Expand Down
Loading