Skip to content

Commit

Permalink
Distributed the issue categories (#53)
Browse files Browse the repository at this point in the history
* Distributed the issue categories
  • Loading branch information
GirZ0n authored Jul 6, 2021
1 parent 175c679 commit e67b1dc
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 17 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Argument | Description
**‑e**, **‑‑end-line** | the end line to be analyzed. The default value is `None`, which meant to handle file by the end.
**‑‑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`.

The output examples:

Expand Down
4 changes: 4 additions & 0 deletions src/python/common/tool_arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ class RunToolArgument(Enum):
'Json string, which contains lists of issues in the previous submissions '
'for other tasks for one user.')

WITH_ALL_CATEGORIES = ArgumentsInfo(None, '--with-all-categories',
'Without this flag, all issues will be categorized into 5 main categories: '
'CODE_STYLE, BEST_PRACTICES, ERROR_PRONE, COMPLEXITY, INFO.')

SOLUTIONS_FILE_PATH = ArgumentsInfo(None, 'solutions_file_path',
'Local XLSX-file or CSV-file path. '
'Your file must include column-names: '
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 @@ -12,6 +12,7 @@ class ApplicationConfig:
allow_duplicates: bool
n_cpu: int
inspectors_config: dict
with_all_categories: bool
start_line: int = 1
end_line: Optional[int] = None
new_format: bool = False
Expand Down
32 changes: 26 additions & 6 deletions src/python/review/inspectors/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,47 @@

@unique
class IssueType(Enum):
# Code style issues
CODE_STYLE = 'CODE_STYLE'
LINE_LEN = 'LINE_LEN'

# Best practice issues
BEST_PRACTICES = 'BEST_PRACTICES'
ERROR_PRONE = 'ERROR_PRONE'
FUNC_LEN = 'FUNC_LEN'
LINE_LEN = 'LINE_LEN'
CYCLOMATIC_COMPLEXITY = 'CYCLOMATIC_COMPLEXITY'
BOOL_EXPR_LEN = 'BOOL_EXPR_LEN'
CLASS_RESPONSE = 'CLASS_RESPONSE'
METHOD_NUMBER = 'METHOD_NUMBER'

# Error-prone issues
ERROR_PRONE = 'ERROR_PRONE'

# Code complexity issues
COMPLEXITY = 'COMPLEXITY'
ARCHITECTURE = 'ARCHITECTURE'
CYCLOMATIC_COMPLEXITY = 'CYCLOMATIC_COMPLEXITY'
INHERITANCE_DEPTH = 'INHERITANCE_DEPTH'
CHILDREN_NUMBER = 'CHILDREN_NUMBER'
WEIGHTED_METHOD = 'WEIGHTED_METHOD'
COUPLING = 'COUPLING'
COHESION = 'COHESION'
CLASS_RESPONSE = 'CLASS_RESPONSE'
METHOD_NUMBER = 'METHOD_NUMBER'
MAINTAINABILITY = 'MAINTAINABILITY'

# Info issues
INFO = 'INFO'

# Others
UNDEFINED = 'UNDEFINED'
ARCHITECTURE = 'ARCHITECTURE' # TODO: Distribute into one of the main types

def __str__(self) -> str:
return ' '.join(self.value.lower().split('_'))

def to_main_type(self) -> 'IssueType':
"""
Converts the issue type to main issue type.
Main issue types: CODE_STYLE, BEST_PRACTICES, ERROR_PRONE, COMPLEXITY, INFO.
"""
return get_main_category_by_issue_type(self)


ISSUE_TYPE_TO_MAIN_CATEGORY = {
# CODE_STYLE
Expand All @@ -60,6 +77,9 @@ def __str__(self) -> str:
IssueType.CHILDREN_NUMBER: IssueType.COMPLEXITY,
IssueType.INHERITANCE_DEPTH: IssueType.COMPLEXITY,
IssueType.ARCHITECTURE: IssueType.COMPLEXITY,

# INFO
IssueType.INFO: IssueType.INFO,
}


Expand Down
2 changes: 2 additions & 0 deletions src/python/review/quality/penalty.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
IssueType.MAINTAINABILITY: 0.3,
IssueType.METHOD_NUMBER: 0.2,
IssueType.WEIGHTED_METHOD: 0.2,
IssueType.UNDEFINED: 0,
IssueType.INFO: 0,
}


Expand Down
6 changes: 3 additions & 3 deletions src/python/review/reviewers/perform_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ def perform_and_print_review(path: Path,

if OutputFormat.JSON == output_format:
if config.new_format:
print_review_result_as_multi_file_json(review_result)
print_review_result_as_multi_file_json(review_result, config)
else:
print_review_result_as_json(review_result)
print_review_result_as_json(review_result, config)
else:
print_review_result_as_text(review_result, path)
print_review_result_as_text(review_result, path, config)

# Don't count INFO issues too
return len(list(filter(lambda issue: issue.type != IssueType.INFO, review_result.all_issues)))
Expand Down
26 changes: 18 additions & 8 deletions src/python/review/reviewers/utils/print_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
from typing import Any, Dict, List

from src.python.evaluation.inspectors.common.statistics import PenaltyIssue
from src.python.review.application_config import ApplicationConfig
from src.python.review.common.file_system import get_file_line
from src.python.review.inspectors.inspector_type import InspectorType
from src.python.review.inspectors.issue import BaseIssue, IssueType
from src.python.review.reviewers.review_result import ReviewResult


def print_review_result_as_text(review_result: ReviewResult,
path: Path) -> None:
path: Path,
config: ApplicationConfig) -> None:
heading = f'\nReview of {str(path)} ({len(review_result.all_issues)} violations)'
print(heading)

Expand All @@ -32,9 +34,13 @@ def print_review_result_as_text(review_result: ReviewResult,
issue.line_no,
).strip()

issue_type = issue.type
if not config.with_all_categories:
issue_type = issue_type.to_main_type()

print(f'{issue.line_no} : '
f'{issue.column_no} : '
f'{issue.type.value} : '
f'{issue_type.value} : '
f'{issue.inspector_type.value} : '
f'{issue.origin_class} : '
f'{issue.description} : '
Expand All @@ -48,7 +54,7 @@ def print_review_result_as_text(review_result: ReviewResult,
print(review_result.general_quality, end='')


def print_review_result_as_json(review_result: ReviewResult) -> None:
def print_review_result_as_json(review_result: ReviewResult, config: ApplicationConfig) -> None:
issues = review_result.all_issues

issues.sort(key=lambda issue: issue.line_no)
Expand All @@ -65,12 +71,12 @@ def print_review_result_as_json(review_result: ReviewResult) -> None:
if quality_with_penalty != quality_without_penalty:
influence_on_penalty = review_result.general_punisher.get_issue_influence_on_penalty(issue.origin_class)

output_json['issues'].append(convert_issue_to_json(issue, influence_on_penalty))
output_json['issues'].append(convert_issue_to_json(issue, config, influence_on_penalty))

print(json.dumps(output_json))


def print_review_result_as_multi_file_json(review_result: ReviewResult) -> None:
def print_review_result_as_multi_file_json(review_result: ReviewResult, config: ApplicationConfig) -> None:
file_review_result_jsons = []

review_result.file_review_results.sort(key=lambda result: result.file_path)
Expand All @@ -94,7 +100,7 @@ def print_review_result_as_multi_file_json(review_result: ReviewResult) -> None:
if quality_with_penalty != quality_without_penalty:
influence_on_penalty = file_review_result.punisher.get_issue_influence_on_penalty(issue.origin_class)

file_review_result_json['issues'].append(convert_issue_to_json(issue, influence_on_penalty))
file_review_result_json['issues'].append(convert_issue_to_json(issue, config, influence_on_penalty))

quality_without_penalty = review_result.general_quality.quality_type
quality_with_penalty = review_result.general_punisher.get_quality_with_penalty(quality_without_penalty)
Expand All @@ -121,16 +127,20 @@ class IssueJsonFields(Enum):
INFLUENCE_ON_PENALTY = 'influence_on_penalty'


def convert_issue_to_json(issue: BaseIssue, influence_on_penalty: int = 0) -> Dict[str, Any]:
def convert_issue_to_json(issue: BaseIssue, config: ApplicationConfig, influence_on_penalty: int = 0) -> Dict[str, Any]:
line_text = get_file_line(issue.file_path, issue.line_no)

issue_type = issue.type
if not config.with_all_categories:
issue_type = issue_type.to_main_type()

return {
IssueJsonFields.CODE.value: issue.origin_class,
IssueJsonFields.TEXT.value: issue.description,
IssueJsonFields.LINE.value: line_text,
IssueJsonFields.LINE_NUMBER.value: issue.line_no,
IssueJsonFields.COLUMN_NUMBER.value: issue.column_no,
IssueJsonFields.CATEGORY.value: issue.type.value,
IssueJsonFields.CATEGORY.value: issue_type.value,
IssueJsonFields.INFLUENCE_ON_PENALTY.value: influence_on_penalty,
}

Expand Down
5 changes: 5 additions & 0 deletions src/python/review/run_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ def configure_arguments(parser: argparse.ArgumentParser) -> None:
help=RunToolArgument.HISTORY.value.description,
type=str)

parser.add_argument(RunToolArgument.WITH_ALL_CATEGORIES.value.long_name,
help=RunToolArgument.WITH_ALL_CATEGORIES.value.description,
action='store_true')


def configure_logging(verbosity: VerbosityLevel) -> None:
if verbosity is VerbosityLevel.ERROR:
Expand Down Expand Up @@ -150,6 +154,7 @@ def main() -> int:
end_line=args.end_line,
new_format=args.new_format,
history=args.history,
with_all_categories=args.with_all_categories,
)

n_issues = perform_and_print_review(args.path, OutputFormat(args.format), config)
Expand Down
1 change: 1 addition & 0 deletions test/python/inspectors/test_local_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def config() -> ApplicationConfig:
allow_duplicates=False,
n_cpu=1,
inspectors_config={"n_cpu": 1},
with_all_categories=False,
)


Expand Down

0 comments on commit e67b1dc

Please sign in to comment.