Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Radon support #19

Merged
merged 40 commits into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 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
43d5193
Added Radon inspector and maintainability index metric
GirZ0n Apr 3, 2021
47cb02e
Added tests for Radon inspector and maintainability metric
GirZ0n Apr 3, 2021
f2d3377
Remove Halstead complexity placeholders
GirZ0n Apr 6, 2021
5a7378f
Add comments
GirZ0n Apr 6, 2021
72075ce
Merge branch 'develop' into radon-support
GirZ0n Apr 6, 2021
ffd212e
Fixed F401
GirZ0n Apr 6, 2021
528599a
Small import refactoring
GirZ0n Apr 6, 2021
9556546
Fixed W293
GirZ0n Apr 6, 2021
ffbcf4c
Trailing commas fix (#20)
GirZ0n Apr 8, 2021
81356dc
Added convert_percentage_of_value_to_lack_of_value
GirZ0n Apr 10, 2021
06553f3
Replaced __get_cohesion_lack with convert_percentage_of_value_to_lack…
GirZ0n Apr 10, 2021
ac4349b
typo fix
GirZ0n Apr 10, 2021
a442f84
Small code refactoring:
GirZ0n Apr 10, 2021
6367493
Removed unused import
GirZ0n Apr 10, 2021
805a492
Small code refactoring:
GirZ0n Apr 10, 2021
62600e3
Added maintainability index tip
GirZ0n Apr 10, 2021
bacb25f
Fixed test
GirZ0n Apr 10, 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,C812,H601 --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,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
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ Python language:
- [x] Pylint [GNU LGPL v2]
* [Site and docs](https://www.pylint.org/)
* [Repository](https://github.com/PyCQA/pylint)


- [x] Radon [MIT]
* [Site and docs](https://radon.readthedocs.io/en/latest/)
* [Repository](https://github.com/rubik/radon)

Java language:

Expand Down Expand Up @@ -92,7 +95,7 @@ Argument | Description
--- | ---
**‑h**, **‑‑help** | show the help message and exit.
**‑v**, **‑‑verbosity** | choose logging level according [this](https://docs.python.org/3/library/logging.html#levels) list: `1` - **ERROR**; `2` - **INFO**; `3` - **DEBUG**; `0` - disable logging (**CRITICAL** value); default value is `0` (**CRITICAL**).
**‑d**, **‑‑disable** | disable inspectors. Available values: for **Python** language: `pylint` for [Pylint](https://github.com/PyCQA/pylint), `flake8` for [flake8](https://flake8.pycqa.org/en/latest/), `python_ast` to check different measures providing by AST; for **Java** language: `checkstyle` for the [Checkstyle](https://checkstyle.sourceforge.io/), `pmd` for [PMD](https://pmd.github.io/); for `Kotlin` language: detekt for [Detekt](https://detekt.github.io/detekt/); for **JavaScript** language: `eslint` for [ESlint](https://eslint.org/). Example: `-d pylint,flake8`.
**‑d**, **‑‑disable** | disable inspectors. Available values: for **Python** language: `pylint` for [Pylint](https://github.com/PyCQA/pylint), `flake8` for [flake8](https://flake8.pycqa.org/en/latest/), `radon` for [Radon](https://radon.readthedocs.io/en/latest/), `python_ast` to check different measures providing by AST; for **Java** language: `checkstyle` for the [Checkstyle](https://checkstyle.sourceforge.io/), `pmd` for [PMD](https://pmd.github.io/); for `Kotlin` language: detekt for [Detekt](https://detekt.github.io/detekt/); for **JavaScript** language: `eslint` for [ESlint](https://eslint.org/). Example: `-d pylint,flake8`.
**‑‑allow-duplicates** | allow duplicate issues found by different linters. By default, duplicates are skipped.
**‑‑language-version**, **‑‑language_version** | specify the language version for JAVA inspectors. Available values: `java7`, `java8`, `java9`, `java11`. **Note**: **‑‑language_version** is deprecated. Will be deleted in the future.
**‑‑n-cpu**, **‑‑n_cpu** | specify number of _cpu_ that can be used to run inspectors. **Note**: **‑‑n_cpu** is deprecated. Will be deleted in the future.
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ flake8-broken-line==0.3.0
flake8-string-format==0.3.0
flake8-commas==2.0.0
cohesion==1.0.0
radon==4.5.0

# extra libraries and frameworks
django==3.0.8
Expand Down
12 changes: 6 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,22 @@ def get_inspectors_additional_files() -> List[str]:
'Topic :: Software Development :: Build Tools',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
'Operating System :: OS Independent'
'Operating System :: OS Independent',
],
keywords='code review',
python_requires='>=3.8, <4',
install_requires=['upsourceapi'],
packages=find_packages(exclude=[
'*.unit_tests', '*.unit_tests.*', 'unit_tests.*', 'unit_tests',
'*.functional_tests', '*.functional_tests.*', 'functional_tests.*', 'functional_tests'
'*.functional_tests', '*.functional_tests.*', 'functional_tests.*', 'functional_tests',
]),
zip_safe=False,
package_data={
'': get_inspectors_additional_files()
'': get_inspectors_additional_files(),
},
entry_points={
'console_scripts': [
'review=review.run_tool:main'
]
}
'review=review.run_tool:main',
],
},
)
2 changes: 1 addition & 1 deletion src/python/review/common/file_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def create_directory(directory: str) -> None:
def get_file_line(path: Path, line_number: int):
return linecache.getline(
str(path),
line_number
line_number,
).strip()


Expand Down
2 changes: 1 addition & 1 deletion src/python/review/common/java_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def javac(javac_args: Union[str, Path]) -> bool:
output_bytes: bytes = subprocess.check_output(
f'javac {javac_args}',
shell=True,
stderr=subprocess.STDOUT
stderr=subprocess.STDOUT,
)
output_str = str(output_bytes, Encoding.UTF_ENCODING.value)

Expand Down
2 changes: 1 addition & 1 deletion src/python/review/common/parallel_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def inspect_in_parallel(path: Path,
with multiprocessing.Pool(config.n_cpu) as pool:
issues = pool.map(
functools.partial(run_inspector, path, config),
inspectors
inspectors,
)

return list(itertools.chain(*issues))
2 changes: 1 addition & 1 deletion src/python/review/common/subprocess_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def run_in_subprocess(command: List[str]) -> str:
process = subprocess.run(
command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
stderr=subprocess.PIPE,
)

stdout = process.stdout.decode()
Expand Down
4 changes: 2 additions & 2 deletions src/python/review/inspectors/checkstyle/checkstyle.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ class CheckstyleInspector(BaseInspector):
r'Boolean expression complexity is (\d+)',

'LineLengthCheck':
r'Line is longer than \d+ characters \(found (\d+)\)'
r'Line is longer than \d+ characters \(found (\d+)\)',
}

@classmethod
def _create_command(cls, path: Path, output_path: Path) -> List[str]:
return [
'java', '-jar', PATH_TOOLS_CHECKSTYLE_JAR,
'-c', PATH_TOOLS_CHECKSTYLE_CONFIG,
'-f', 'xml', '-o', output_path, str(path)
'-f', 'xml', '-o', output_path, str(path),
]

def inspect(self, path: Path, config: dict) -> List[BaseIssue]:
Expand Down
12 changes: 12 additions & 0 deletions src/python/review/inspectors/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from math import floor


def convert_percentage_of_value_to_lack_of_value(percentage_of_value: float) -> int:
"""
Converts percentage of value to lack of value.
Calculated by the formula: floor(100 - percentage_of_value).

:param percentage_of_value: value in the range from 0 to 100.
:return: lack of value.
"""
return floor(100 - percentage_of_value)
4 changes: 2 additions & 2 deletions src/python/review/inspectors/detekt/detekt.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class DetektInspector(BaseInspector):
'ComplexCondition':
r'This condition is too complex \((\d+)\)',
'ComplexMethod':
r'The function .* appears to be too complex \((\d+)\)'
r'The function .* appears to be too complex \((\d+)\)',
}

@classmethod
Expand All @@ -38,7 +38,7 @@ def _create_command(cls, path: Path, output_path: Path):
'--config', PATH_DETEKT_CONFIG,
'--plugins', PATH_DETEKT_PLUGIN,
'--report', f'xml:{output_path}',
'--input', str(path)
'--input', str(path),
]

def inspect(self, path: Path, config) -> List[BaseIssue]:
Expand Down
2 changes: 1 addition & 1 deletion src/python/review/inspectors/eslint/eslint.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ESLintInspector(BaseInspector):

origin_class_to_pattern = {
'complexity':
r'complexity of (\d+)'
r'complexity of (\d+)',
}

@classmethod
Expand Down
3 changes: 1 addition & 2 deletions src/python/review/inspectors/flake8/.flake8
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,4 @@ ignore=W291, # trailing whitespaces
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

C814, # missing trailing comma in Python 2
17 changes: 4 additions & 13 deletions src/python/review/inspectors/flake8/flake8.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
import math
import re
from pathlib import Path
from typing import List
Expand All @@ -17,6 +16,7 @@
CohesionIssue,
)
from src.python.review.inspectors.tips import get_cyclomatic_complexity_tip
from src.python.review.inspectors.common import convert_percentage_of_value_to_lack_of_value

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -69,7 +69,9 @@ def parse(cls, output: str) -> List[BaseIssue]:
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.COHESION_LACK.value] = convert_percentage_of_value_to_lack_of_value(
float(cohesion_match.group(1)),
)
issue_data[IssueData.ISSUE_TYPE.value] = IssueType.COHESION
issues.append(CohesionIssue(**issue_data))
else:
Expand Down Expand Up @@ -98,14 +100,3 @@ 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)
2 changes: 2 additions & 0 deletions src/python/review/inspectors/inspector_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class InspectorType(Enum):
PYLINT = 'PYLINT'
PYTHON_AST = 'PYTHON_AST'
FLAKE8 = 'FLAKE8'
RADON = 'RADON'

# Java language
PMD = 'PMD'
Expand All @@ -29,6 +30,7 @@ def available_values(cls) -> List[str]:
cls.PYLINT.value,
cls.FLAKE8.value,
cls.PYTHON_AST.value,
cls.RADON.value,

# Java language
cls.PMD.value,
Expand Down
8 changes: 4 additions & 4 deletions src/python/review/inspectors/intellij/intellij.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def __init__(self):
def create_command(output_dir_path) -> List[Union[str, Path]]:
return [
INTELLIJ_INSPECTOR_EXECUTABLE, INTELLIJ_INSPECTOR_PROJECT,
INTELLIJ_INSPECTOR_SETTINGS, output_dir_path, '-v2'
INTELLIJ_INSPECTOR_SETTINGS, output_dir_path, '-v2',
]

def inspect(self, path: Path, config: dict) -> List[BaseIssue]:
Expand Down Expand Up @@ -134,8 +134,8 @@ def parse(cls, out_dir_path: Path,
file_path = Path(
text.replace(
'file://$PROJECT_DIR$',
str(INTELLIJ_INSPECTOR_PROJECT)
)
str(INTELLIJ_INSPECTOR_PROJECT),
),
)
elif tag == 'line':
line_no = int(text)
Expand All @@ -160,7 +160,7 @@ def parse(cls, out_dir_path: Path,
description=description,
origin_class=issue_class,
inspector_type=cls.inspector_type,
type=issue_type
type=issue_type,
))

return issues
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,5 +378,5 @@
'\'when\' that can be simplified by introducing an argument':
IssueType.CODE_STYLE,

'Annotator': IssueType.ERROR_PRONE
'Annotator': IssueType.ERROR_PRONE,
}
13 changes: 12 additions & 1 deletion src/python/review/inspectors/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class IssueType(Enum):
COHESION = 'COHESION'
CLASS_RESPONSE = 'CLASS_RESPONSE'
METHOD_NUMBER = 'METHOD_NUMBER'
MAINTAINABILITY = 'MAINTAINABILITY'


# Keys in results dictionary
Expand All @@ -46,6 +47,7 @@ class IssueData(Enum):
BOOL_EXPR_LEN = 'bool_expr_len'
CYCLOMATIC_COMPLEXITY = 'cc_value'
COHESION_LACK = 'cohesion_lack'
MAINTAINABILITY_LACK = 'maintainability_lack'

@classmethod
def get_base_issue_data_dict(cls,
Expand All @@ -59,7 +61,7 @@ def get_base_issue_data_dict(cls,
cls.LINE_NUMBER.value: line_number,
cls.COLUMN_NUMBER.value: column_number,
cls.ORIGIN_ClASS.value: origin_class,
cls.INSPECTOR_TYPE.value: inspector_type
cls.INSPECTOR_TYPE.value: inspector_type,
}


Expand Down Expand Up @@ -184,3 +186,12 @@ class MethodNumberIssue(BaseIssue, Measurable):

def measure(self) -> int:
return self.method_number


@dataclass(frozen=True)
class MaintainabilityLackIssue(BaseIssue, Measurable):
maintainability_lack: int
type = IssueType.MAINTAINABILITY

def measure(self) -> int:
return self.maintainability_lack
2 changes: 1 addition & 1 deletion src/python/review/inspectors/pmd/pmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def _create_command(cls, path: Path,
'-language', 'java',
'-version', java_version.value,
'-f', 'csv', '-r', str(output_path),
'-t', str(n_cpu)
'-t', str(n_cpu),
]

def inspect(self, path: Path, config: dict) -> List[BaseIssue]:
Expand Down
14 changes: 7 additions & 7 deletions src/python/review/inspectors/pyast/python_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def visit(self, node: ast.AST):
origin_class=BOOL_EXPR_LEN_ORIGIN_CLASS,
inspector_type=self._inspector_type,
bool_expr_len=length,
type=IssueType.BOOL_EXPR_LEN
type=IssueType.BOOL_EXPR_LEN,
))


Expand All @@ -58,7 +58,7 @@ def __init__(self, content: str, file_path: Path, inspector_type: InspectorType)
def visit(self, node):
if isinstance(self._previous_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
func_length = self._find_func_len(
self._previous_node.lineno, node.lineno
self._previous_node.lineno, node.lineno,
)

self._function_lens.append(FuncLenIssue(
Expand All @@ -69,7 +69,7 @@ def visit(self, node):
origin_class=FUNC_LEN_ORIGIN_CLASS,
inspector_type=self._inspector_type,
func_len=func_length,
type=IssueType.FUNC_LEN
type=IssueType.FUNC_LEN,
))

self._previous_node = node
Expand All @@ -80,7 +80,7 @@ def visit(self, node):
def function_lens(self) -> List[FuncLenIssue]:
if isinstance(self._previous_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
func_length = self._find_func_len(
self._previous_node.lineno, self._n_lines + 1
self._previous_node.lineno, self._n_lines + 1,
)

self._function_lens.append(FuncLenIssue(
Expand All @@ -91,7 +91,7 @@ def function_lens(self) -> List[FuncLenIssue]:
origin_class=FUNC_LEN_ORIGIN_CLASS,
inspector_type=self._inspector_type,
func_len=func_length,
type=IssueType.FUNC_LEN
type=IssueType.FUNC_LEN,
))

self._previous_node = None
Expand Down Expand Up @@ -125,13 +125,13 @@ def inspect(cls, path: Path, config: dict) -> List[BaseIssue]:
bool_gatherer = BoolExpressionLensGatherer(path_to_file, cls.inspector_type)
bool_gatherer.visit(tree)
metrics.extend(
bool_gatherer.bool_expression_lens
bool_gatherer.bool_expression_lens,
)

func_gatherer = FunctionLensGatherer(file_content, path_to_file, cls.inspector_type)
func_gatherer.visit(tree)
metrics.extend(
func_gatherer.function_lens
func_gatherer.function_lens,
)

return metrics
Expand Down
6 changes: 3 additions & 3 deletions src/python/review/inspectors/pylint/pylint.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class PylintInspector(BaseInspector):
supported_issue_types = (
IssueType.CODE_STYLE,
IssueType.BEST_PRACTICES,
IssueType.ERROR_PRONE
IssueType.ERROR_PRONE,
)

@classmethod
Expand All @@ -31,7 +31,7 @@ def inspect(cls, path: Path, config: dict) -> List[CodeIssue]:
'--load-plugins', 'pylint_django',
f'--rcfile={PATH_PYLINT_CONFIG}',
f'--msg-template={MSG_TEMPLATE}',
str(path)
str(path),
]

output = run_in_subprocess(command)
Expand Down Expand Up @@ -70,7 +70,7 @@ def parse(cls, output: str) -> List[CodeIssue]:
origin_class=origin_class,
description=description,
inspector_type=cls.inspector_type,
type=issue_type
type=issue_type,
))

return issues
Expand Down
Empty file.
Loading