complexipy 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {complexipy-0.3.0 → complexipy-0.3.2}/Cargo.lock +1 -1
- {complexipy-0.3.0 → complexipy-0.3.2}/Cargo.toml +2 -2
- {complexipy-0.3.0 → complexipy-0.3.2}/PKG-INFO +21 -16
- {complexipy-0.3.0 → complexipy-0.3.2}/README.md +18 -13
- {complexipy-0.3.0 → complexipy-0.3.2}/complexipy/main.py +14 -4
- {complexipy-0.3.0 → complexipy-0.3.2}/complexipy/types.py +6 -0
- {complexipy-0.3.0 → complexipy-0.3.2}/complexipy/utils.py +49 -25
- {complexipy-0.3.0 → complexipy-0.3.2}/docs/index.md +18 -13
- {complexipy-0.3.0 → complexipy-0.3.2}/pyproject.toml +1 -1
- {complexipy-0.3.0 → complexipy-0.3.2}/src/cognitive_complexity/mod.rs +6 -1
- {complexipy-0.3.0 → complexipy-0.3.2}/src/cognitive_complexity/utils.rs +66 -18
- {complexipy-0.3.0 → complexipy-0.3.2}/LICENSE +0 -0
- {complexipy-0.3.0 → complexipy-0.3.2}/complexipy/__init__.py +0 -0
- {complexipy-0.3.0 → complexipy-0.3.2}/docs/img/favicon.svg +0 -0
- {complexipy-0.3.0 → complexipy-0.3.2}/docs/img/icon.svg +0 -0
- {complexipy-0.3.0 → complexipy-0.3.2}/docs/img/logo-vector.svg +0 -0
- {complexipy-0.3.0 → complexipy-0.3.2}/mkdocs.yml +0 -0
- {complexipy-0.3.0 → complexipy-0.3.2}/src/classes/mod.rs +0 -0
- {complexipy-0.3.0 → complexipy-0.3.2}/src/lib.rs +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "complexipy"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.2"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Robin Quintero <rohaquinlop301@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
7
|
-
description = "An extremely fast Python library to calculate the cognitive complexity of
|
|
7
|
+
description = "An extremely fast Python library to calculate the cognitive complexity of Python files, written in Rust."
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
homepage = "https://github.com/rohaquinlop/complexipy"
|
|
10
10
|
documentation = "https://rohaquinlop.github.io/complexipy/"
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: complexipy
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
7
|
Requires-Dist: typer[all]
|
|
8
8
|
License-File: LICENSE
|
|
9
|
-
Summary: An extremely fast Python library to calculate the cognitive complexity of
|
|
9
|
+
Summary: An extremely fast Python library to calculate the cognitive complexity of Python files, written in Rust.
|
|
10
10
|
Keywords: cognitive,complexity,cognitive complexity,rust,fast
|
|
11
11
|
Home-Page: https://github.com/rohaquinlop/complexipy
|
|
12
12
|
Author: Robin Quintero <rohaquinlop301@gmail.com>
|
|
13
13
|
Author-email: Robin Quintero <rohaquinlop301@gmail.com>
|
|
14
14
|
License: MIT
|
|
15
|
-
Requires-Python: >=3.
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
16
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
17
17
|
Project-URL: Source Code, https://github.com/rohaquinlop/complexipy
|
|
18
18
|
|
|
@@ -65,7 +65,7 @@ Made with [contributors-img](https://contrib.rocks)
|
|
|
65
65
|
|
|
66
66
|
## Requirements
|
|
67
67
|
|
|
68
|
-
- Python >= 3.
|
|
68
|
+
- Python >= 3.8
|
|
69
69
|
- You also need to install `git` in your computer if you want to analyze a git repository.
|
|
70
70
|
|
|
71
71
|
## Installation
|
|
@@ -79,16 +79,17 @@ pip install complexipy
|
|
|
79
79
|
To run **complexipy** you can use the following command:
|
|
80
80
|
|
|
81
81
|
```shell
|
|
82
|
-
complexipy .
|
|
83
|
-
complexipy path/to/directory
|
|
84
|
-
complexipy git_repository_url
|
|
85
|
-
complexipy path/to/file.py
|
|
86
|
-
complexipy path/to/file.py -c 20
|
|
87
|
-
complexipy path/to/directory -c 0
|
|
88
|
-
complexipy path/to/directory -o
|
|
89
|
-
complexipy path/to/directory -d low
|
|
90
|
-
complexipy path/to/directory -l file
|
|
91
|
-
complexipy path/to/directory -q
|
|
82
|
+
complexipy . # Use complexipy to analyze the current directory and any subdirectories
|
|
83
|
+
complexipy path/to/directory # Use complexipy to analyze a specific directory and any subdirectories
|
|
84
|
+
complexipy git_repository_url # Use complexipy to analyze a git repository
|
|
85
|
+
complexipy path/to/file.py # Use complexipy to analyze a specific file
|
|
86
|
+
complexipy path/to/file.py -c 20 # Use the -c option to set the maximum congnitive complexity, default is 15
|
|
87
|
+
complexipy path/to/directory -c 0 # Set the maximum cognitive complexity to 0 to disable the exit with error
|
|
88
|
+
complexipy path/to/directory -o # Use the -o option to output the results to a CSV file, default is False
|
|
89
|
+
complexipy path/to/directory -d low # Use the -d option to set detail level, default is "normal". If set to "low" will show only files with complexity greater than the maximum complexity
|
|
90
|
+
complexipy path/to/directory -l file # Use the -l option to set the level of measurement, default is "function". If set to "file" will measure the complexity of the file and will validate the maximum complexity according to the file complexity.
|
|
91
|
+
complexipy path/to/directory -q # Use the -q option to disable the output to the console, default is False.
|
|
92
|
+
complexipy path/to/directory -s desc # Use the -s option to set the sort order, default is "asc". If set to "desc" will sort the results in descending order. If set to "asc" will sort the results in ascending order. If set to "name" will sort the results by name.
|
|
92
93
|
```
|
|
93
94
|
|
|
94
95
|
### Options
|
|
@@ -99,7 +100,7 @@ complexipy path/to/directory -q # Use the -q option to disable the output to
|
|
|
99
100
|
If set to 0, the exit with error will be disabled.
|
|
100
101
|
- `-o` or `--output`: Output the results to a CSV file, default is False. The
|
|
101
102
|
filename will be `complexipy.csv` and will be saved in the invocation directory.
|
|
102
|
-
- `-d` or `--
|
|
103
|
+
- `-d` or `--details`: Set the detail level, default is "normal". If set to "low"
|
|
103
104
|
will show only files or functions with complexity greater than the maximum
|
|
104
105
|
complexity.
|
|
105
106
|
- `-l` or `--level` Set the level of measurement, default is "function". If set
|
|
@@ -110,6 +111,10 @@ complexipy path/to/directory -q # Use the -q option to disable the output to
|
|
|
110
111
|
a maximum complexity according for each file or for each function in the file
|
|
111
112
|
(or files).
|
|
112
113
|
- `-q` or `--quiet`: Disable the output to the console, default is False.
|
|
114
|
+
- `-s` or `--sort`: Set the sort order, default is "asc". If set to "desc" will
|
|
115
|
+
sort the results in descending order. If set to "asc" will sort the results in
|
|
116
|
+
ascending order. If set to "name" will sort the results by name. This option will
|
|
117
|
+
affect the output to the console and the output to the CSV file.
|
|
113
118
|
|
|
114
119
|
If the cognitive complexity of a file or a function is greater than the maximum
|
|
115
120
|
cognitive cognitive complexity, then the return code will be 1 and exit with
|
|
@@ -139,7 +144,7 @@ The cognitive complexity of the file is 1, and the output of the command
|
|
|
139
144
|
`complexipy path/to/file.py` will be:
|
|
140
145
|
|
|
141
146
|
```txt
|
|
142
|
-
───────────────────────────── 🐙 complexipy 0.3.
|
|
147
|
+
───────────────────────────── 🐙 complexipy 0.3.2 ──────────────────────────────
|
|
143
148
|
Summary
|
|
144
149
|
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
|
|
145
150
|
┃ Path ┃ File ┃ Function ┃ Complexity ┃
|
|
@@ -47,7 +47,7 @@ Made with [contributors-img](https://contrib.rocks)
|
|
|
47
47
|
|
|
48
48
|
## Requirements
|
|
49
49
|
|
|
50
|
-
- Python >= 3.
|
|
50
|
+
- Python >= 3.8
|
|
51
51
|
- You also need to install `git` in your computer if you want to analyze a git repository.
|
|
52
52
|
|
|
53
53
|
## Installation
|
|
@@ -61,16 +61,17 @@ pip install complexipy
|
|
|
61
61
|
To run **complexipy** you can use the following command:
|
|
62
62
|
|
|
63
63
|
```shell
|
|
64
|
-
complexipy .
|
|
65
|
-
complexipy path/to/directory
|
|
66
|
-
complexipy git_repository_url
|
|
67
|
-
complexipy path/to/file.py
|
|
68
|
-
complexipy path/to/file.py -c 20
|
|
69
|
-
complexipy path/to/directory -c 0
|
|
70
|
-
complexipy path/to/directory -o
|
|
71
|
-
complexipy path/to/directory -d low
|
|
72
|
-
complexipy path/to/directory -l file
|
|
73
|
-
complexipy path/to/directory -q
|
|
64
|
+
complexipy . # Use complexipy to analyze the current directory and any subdirectories
|
|
65
|
+
complexipy path/to/directory # Use complexipy to analyze a specific directory and any subdirectories
|
|
66
|
+
complexipy git_repository_url # Use complexipy to analyze a git repository
|
|
67
|
+
complexipy path/to/file.py # Use complexipy to analyze a specific file
|
|
68
|
+
complexipy path/to/file.py -c 20 # Use the -c option to set the maximum congnitive complexity, default is 15
|
|
69
|
+
complexipy path/to/directory -c 0 # Set the maximum cognitive complexity to 0 to disable the exit with error
|
|
70
|
+
complexipy path/to/directory -o # Use the -o option to output the results to a CSV file, default is False
|
|
71
|
+
complexipy path/to/directory -d low # Use the -d option to set detail level, default is "normal". If set to "low" will show only files with complexity greater than the maximum complexity
|
|
72
|
+
complexipy path/to/directory -l file # Use the -l option to set the level of measurement, default is "function". If set to "file" will measure the complexity of the file and will validate the maximum complexity according to the file complexity.
|
|
73
|
+
complexipy path/to/directory -q # Use the -q option to disable the output to the console, default is False.
|
|
74
|
+
complexipy path/to/directory -s desc # Use the -s option to set the sort order, default is "asc". If set to "desc" will sort the results in descending order. If set to "asc" will sort the results in ascending order. If set to "name" will sort the results by name.
|
|
74
75
|
```
|
|
75
76
|
|
|
76
77
|
### Options
|
|
@@ -81,7 +82,7 @@ complexipy path/to/directory -q # Use the -q option to disable the output to
|
|
|
81
82
|
If set to 0, the exit with error will be disabled.
|
|
82
83
|
- `-o` or `--output`: Output the results to a CSV file, default is False. The
|
|
83
84
|
filename will be `complexipy.csv` and will be saved in the invocation directory.
|
|
84
|
-
- `-d` or `--
|
|
85
|
+
- `-d` or `--details`: Set the detail level, default is "normal". If set to "low"
|
|
85
86
|
will show only files or functions with complexity greater than the maximum
|
|
86
87
|
complexity.
|
|
87
88
|
- `-l` or `--level` Set the level of measurement, default is "function". If set
|
|
@@ -92,6 +93,10 @@ complexipy path/to/directory -q # Use the -q option to disable the output to
|
|
|
92
93
|
a maximum complexity according for each file or for each function in the file
|
|
93
94
|
(or files).
|
|
94
95
|
- `-q` or `--quiet`: Disable the output to the console, default is False.
|
|
96
|
+
- `-s` or `--sort`: Set the sort order, default is "asc". If set to "desc" will
|
|
97
|
+
sort the results in descending order. If set to "asc" will sort the results in
|
|
98
|
+
ascending order. If set to "name" will sort the results by name. This option will
|
|
99
|
+
affect the output to the console and the output to the CSV file.
|
|
95
100
|
|
|
96
101
|
If the cognitive complexity of a file or a function is greater than the maximum
|
|
97
102
|
cognitive cognitive complexity, then the return code will be 1 and exit with
|
|
@@ -121,7 +126,7 @@ The cognitive complexity of the file is 1, and the output of the command
|
|
|
121
126
|
`complexipy path/to/file.py` will be:
|
|
122
127
|
|
|
123
128
|
```txt
|
|
124
|
-
───────────────────────────── 🐙 complexipy 0.3.
|
|
129
|
+
───────────────────────────── 🐙 complexipy 0.3.2 ──────────────────────────────
|
|
125
130
|
Summary
|
|
126
131
|
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
|
|
127
132
|
┃ Path ┃ File ┃ Function ┃ Complexity ┃
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from .types import (
|
|
2
2
|
DetailTypes,
|
|
3
3
|
Level,
|
|
4
|
+
Sort,
|
|
4
5
|
)
|
|
5
6
|
from .utils import (
|
|
6
7
|
output_summary,
|
|
@@ -27,7 +28,7 @@ import typer
|
|
|
27
28
|
root_dir = Path(__file__).resolve().parent.parent
|
|
28
29
|
app = typer.Typer(name="complexipy")
|
|
29
30
|
console = Console()
|
|
30
|
-
version = "0.3.
|
|
31
|
+
version = "0.3.2"
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
@app.command()
|
|
@@ -59,6 +60,12 @@ def main(
|
|
|
59
60
|
quiet: bool = typer.Option(
|
|
60
61
|
False, "--quiet", "-q", help="Suppress the output to the console."
|
|
61
62
|
),
|
|
63
|
+
sort: Sort = typer.Option(
|
|
64
|
+
Sort.asc.value,
|
|
65
|
+
"--sort",
|
|
66
|
+
"-s",
|
|
67
|
+
help="Sort the output by complexity, it can be 'asc', 'desc' or 'name'. Default is 'asc'.",
|
|
68
|
+
),
|
|
62
69
|
):
|
|
63
70
|
is_dir = Path(path).is_dir()
|
|
64
71
|
_url_pattern = (
|
|
@@ -77,22 +84,25 @@ def main(
|
|
|
77
84
|
output_csv_path = f"{invocation_path}/complexipy.csv"
|
|
78
85
|
|
|
79
86
|
if output and file_level:
|
|
80
|
-
rust.output_csv_file_level(output_csv_path, files)
|
|
87
|
+
rust.output_csv_file_level(output_csv_path, files, sort.value)
|
|
81
88
|
console.print(f"Results saved in {output_csv_path}")
|
|
82
89
|
if output and not file_level:
|
|
83
|
-
rust.output_csv_function_level(output_csv_path, files)
|
|
90
|
+
rust.output_csv_function_level(output_csv_path, files, sort.value)
|
|
84
91
|
console.print(f"Results saved in {output_csv_path}")
|
|
85
92
|
|
|
86
93
|
# Summary
|
|
87
94
|
if not quiet:
|
|
88
95
|
has_success = output_summary(
|
|
89
|
-
console, file_level, files, max_complexity, details, path,
|
|
96
|
+
console, file_level, files, max_complexity, details, path, sort
|
|
90
97
|
)
|
|
91
98
|
if quiet and not file_level:
|
|
92
99
|
has_success = has_success_function_level(files, max_complexity)
|
|
93
100
|
if quiet and file_level:
|
|
94
101
|
has_success = has_success_file_level(files, max_complexity)
|
|
95
102
|
|
|
103
|
+
console.print(
|
|
104
|
+
f"{len(files)} file{'s' if len(files)> 1 else ''} analyzed in {execution_time:.4f} seconds"
|
|
105
|
+
)
|
|
96
106
|
console.rule(":tada: Analysis completed! :tada:")
|
|
97
107
|
|
|
98
108
|
if not has_success:
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
from .types import (
|
|
2
2
|
DetailTypes,
|
|
3
|
+
Sort,
|
|
3
4
|
)
|
|
4
5
|
from complexipy.rust import (
|
|
5
6
|
FileComplexity,
|
|
7
|
+
FunctionComplexity,
|
|
6
8
|
)
|
|
7
9
|
from rich.align import (
|
|
8
10
|
Align,
|
|
@@ -20,27 +22,28 @@ def output_summary(
|
|
|
20
22
|
max_complexity: int,
|
|
21
23
|
details: DetailTypes,
|
|
22
24
|
path: str,
|
|
23
|
-
|
|
25
|
+
sort: Sort,
|
|
24
26
|
) -> bool:
|
|
25
27
|
if file_level:
|
|
26
28
|
table, has_success, total_complexity = create_table_file_level(
|
|
27
|
-
files, max_complexity, details
|
|
29
|
+
files, max_complexity, details, sort
|
|
28
30
|
)
|
|
29
31
|
else:
|
|
30
32
|
table, has_success, total_complexity = create_table_function_level(
|
|
31
|
-
files, max_complexity, details
|
|
33
|
+
files, max_complexity, details, sort
|
|
32
34
|
)
|
|
33
|
-
|
|
35
|
+
|
|
36
|
+
if details == DetailTypes.low and table.row_count < 1:
|
|
37
|
+
console.print(f"No {'file' if file_level else 'function'}{'s' if len(files) > 1 else ''} were found with complexity greater than {max_complexity}.")
|
|
38
|
+
else:
|
|
39
|
+
console.print(Align.center(table))
|
|
34
40
|
console.print(f":brain: Total Cognitive Complexity in {path}: {total_complexity}")
|
|
35
|
-
console.print(
|
|
36
|
-
f"{len(files)} file{'s' if len(files)> 1 else ''} analyzed in {execution_time:.4f} seconds"
|
|
37
|
-
)
|
|
38
41
|
|
|
39
42
|
return has_success
|
|
40
43
|
|
|
41
44
|
|
|
42
45
|
def create_table_file_level(
|
|
43
|
-
files: list[FileComplexity], max_complexity: int, details: DetailTypes
|
|
46
|
+
files: list[FileComplexity], max_complexity: int, details: DetailTypes, sort: Sort
|
|
44
47
|
) -> tuple[Table, bool, int]:
|
|
45
48
|
has_success = True
|
|
46
49
|
|
|
@@ -51,6 +54,13 @@ def create_table_file_level(
|
|
|
51
54
|
table.add_column("File")
|
|
52
55
|
table.add_column("Complexity")
|
|
53
56
|
total_complexity = 0
|
|
57
|
+
|
|
58
|
+
if sort != Sort.name:
|
|
59
|
+
files.sort(key=lambda x: x.complexity)
|
|
60
|
+
|
|
61
|
+
if sort == Sort.desc:
|
|
62
|
+
files.reverse()
|
|
63
|
+
|
|
54
64
|
for file in files:
|
|
55
65
|
total_complexity += file.complexity
|
|
56
66
|
if file.complexity > max_complexity and max_complexity != 0:
|
|
@@ -70,9 +80,14 @@ def create_table_file_level(
|
|
|
70
80
|
|
|
71
81
|
|
|
72
82
|
def create_table_function_level(
|
|
73
|
-
files: list[FileComplexity],
|
|
83
|
+
files: list[FileComplexity],
|
|
84
|
+
complexity: int,
|
|
85
|
+
details: DetailTypes,
|
|
86
|
+
sort: bool = False,
|
|
74
87
|
) -> tuple[Table, bool, int]:
|
|
75
88
|
has_success = True
|
|
89
|
+
all_functions: list[tuple[str, str, FunctionComplexity]] = []
|
|
90
|
+
total_complexity = 0
|
|
76
91
|
|
|
77
92
|
table = Table(
|
|
78
93
|
title="Summary", show_header=True, header_style="bold magenta", show_lines=True
|
|
@@ -81,26 +96,35 @@ def create_table_function_level(
|
|
|
81
96
|
table.add_column("File")
|
|
82
97
|
table.add_column("Function")
|
|
83
98
|
table.add_column("Complexity")
|
|
84
|
-
|
|
99
|
+
|
|
85
100
|
for file in files:
|
|
86
101
|
total_complexity += file.complexity
|
|
87
102
|
for function in file.functions:
|
|
88
103
|
total_complexity += function.complexity
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
all_functions.append((file.path, file.file_name, function))
|
|
105
|
+
|
|
106
|
+
if sort != Sort.name:
|
|
107
|
+
all_functions.sort(key=lambda x: x[2].complexity)
|
|
108
|
+
|
|
109
|
+
if sort == Sort.desc:
|
|
110
|
+
all_functions.reverse()
|
|
111
|
+
|
|
112
|
+
for function in all_functions:
|
|
113
|
+
if function[2].complexity > complexity and complexity != 0:
|
|
114
|
+
table.add_row(
|
|
115
|
+
f"{function[0]}",
|
|
116
|
+
f"[green]{function[1]}[/green]",
|
|
117
|
+
f"[green]{function[2].name}[/green]",
|
|
118
|
+
f"[red]{function[2].complexity}[/red]",
|
|
119
|
+
)
|
|
120
|
+
has_success = False
|
|
121
|
+
elif details != DetailTypes.low or complexity == 0:
|
|
122
|
+
table.add_row(
|
|
123
|
+
f"{function[0]}",
|
|
124
|
+
f"[green]{function[1]}[/green]",
|
|
125
|
+
f"[green]{function[2].name}[/green]",
|
|
126
|
+
f"[blue]{function[2].complexity}[/blue]",
|
|
127
|
+
)
|
|
104
128
|
return table, has_success, total_complexity
|
|
105
129
|
|
|
106
130
|
|
|
@@ -47,7 +47,7 @@ Made with [contributors-img](https://contrib.rocks)
|
|
|
47
47
|
|
|
48
48
|
## Requirements
|
|
49
49
|
|
|
50
|
-
- Python >= 3.
|
|
50
|
+
- Python >= 3.8
|
|
51
51
|
- You also need to install `git` in your computer if you want to analyze a git repository.
|
|
52
52
|
|
|
53
53
|
## Installation
|
|
@@ -61,16 +61,17 @@ pip install complexipy
|
|
|
61
61
|
To run **complexipy** you can use the following command:
|
|
62
62
|
|
|
63
63
|
```shell
|
|
64
|
-
complexipy .
|
|
65
|
-
complexipy path/to/directory
|
|
66
|
-
complexipy git_repository_url
|
|
67
|
-
complexipy path/to/file.py
|
|
68
|
-
complexipy path/to/file.py -c 20
|
|
69
|
-
complexipy path/to/directory -c 0
|
|
70
|
-
complexipy path/to/directory -o
|
|
71
|
-
complexipy path/to/directory -d low
|
|
72
|
-
complexipy path/to/directory -l file
|
|
73
|
-
complexipy path/to/directory -q
|
|
64
|
+
complexipy . # Use complexipy to analyze the current directory and any subdirectories
|
|
65
|
+
complexipy path/to/directory # Use complexipy to analyze a specific directory and any subdirectories
|
|
66
|
+
complexipy git_repository_url # Use complexipy to analyze a git repository
|
|
67
|
+
complexipy path/to/file.py # Use complexipy to analyze a specific file
|
|
68
|
+
complexipy path/to/file.py -c 20 # Use the -c option to set the maximum congnitive complexity, default is 15
|
|
69
|
+
complexipy path/to/directory -c 0 # Set the maximum cognitive complexity to 0 to disable the exit with error
|
|
70
|
+
complexipy path/to/directory -o # Use the -o option to output the results to a CSV file, default is False
|
|
71
|
+
complexipy path/to/directory -d low # Use the -d option to set detail level, default is "normal". If set to "low" will show only files with complexity greater than the maximum complexity
|
|
72
|
+
complexipy path/to/directory -l file # Use the -l option to set the level of measurement, default is "function". If set to "file" will measure the complexity of the file and will validate the maximum complexity according to the file complexity.
|
|
73
|
+
complexipy path/to/directory -q # Use the -q option to disable the output to the console, default is False.
|
|
74
|
+
complexipy path/to/directory -s desc # Use the -s option to set the sort order, default is "asc". If set to "desc" will sort the results in descending order. If set to "asc" will sort the results in ascending order. If set to "name" will sort the results by name.
|
|
74
75
|
```
|
|
75
76
|
|
|
76
77
|
### Options
|
|
@@ -81,7 +82,7 @@ complexipy path/to/directory -q # Use the -q option to disable the output to
|
|
|
81
82
|
If set to 0, the exit with error will be disabled.
|
|
82
83
|
- `-o` or `--output`: Output the results to a CSV file, default is False. The
|
|
83
84
|
filename will be `complexipy.csv` and will be saved in the invocation directory.
|
|
84
|
-
- `-d` or `--
|
|
85
|
+
- `-d` or `--details`: Set the detail level, default is "normal". If set to "low"
|
|
85
86
|
will show only files or functions with complexity greater than the maximum
|
|
86
87
|
complexity.
|
|
87
88
|
- `-l` or `--level` Set the level of measurement, default is "function". If set
|
|
@@ -92,6 +93,10 @@ complexipy path/to/directory -q # Use the -q option to disable the output to
|
|
|
92
93
|
a maximum complexity according for each file or for each function in the file
|
|
93
94
|
(or files).
|
|
94
95
|
- `-q` or `--quiet`: Disable the output to the console, default is False.
|
|
96
|
+
- `-s` or `--sort`: Set the sort order, default is "asc". If set to "desc" will
|
|
97
|
+
sort the results in descending order. If set to "asc" will sort the results in
|
|
98
|
+
ascending order. If set to "name" will sort the results by name. This option will
|
|
99
|
+
affect the output to the console and the output to the CSV file.
|
|
95
100
|
|
|
96
101
|
If the cognitive complexity of a file or a function is greater than the maximum
|
|
97
102
|
cognitive cognitive complexity, then the return code will be 1 and exit with
|
|
@@ -121,7 +126,7 @@ The cognitive complexity of the file is 1, and the output of the command
|
|
|
121
126
|
`complexipy path/to/file.py` will be:
|
|
122
127
|
|
|
123
128
|
```txt
|
|
124
|
-
───────────────────────────── 🐙 complexipy 0.3.
|
|
129
|
+
───────────────────────────── 🐙 complexipy 0.3.2 ──────────────────────────────
|
|
125
130
|
Summary
|
|
126
131
|
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
|
|
127
132
|
┃ Path ┃ File ┃ Function ┃ Complexity ┃
|
|
@@ -5,7 +5,7 @@ build-backend = "maturin"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "complexipy"
|
|
7
7
|
keywords = ["cognitive", "complexity", "cognitive complexity", "rust", "fast"]
|
|
8
|
-
requires-python = ">=3.
|
|
8
|
+
requires-python = ">=3.8"
|
|
9
9
|
classifiers = [
|
|
10
10
|
"Programming Language :: Rust",
|
|
11
11
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
@@ -271,7 +271,12 @@ fn statement_cognitive_complexity(statement: Stmt, nesting_level: u64) -> PyResu
|
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
273
|
Stmt::Assign(a) => {
|
|
274
|
-
|
|
274
|
+
match *a.value {
|
|
275
|
+
ast::Expr::IfExp(..) => {
|
|
276
|
+
complexity += count_bool_ops(*a.value);
|
|
277
|
+
}
|
|
278
|
+
_ => {}
|
|
279
|
+
}
|
|
275
280
|
|
|
276
281
|
if complexity > 0 {
|
|
277
282
|
complexity += nesting_level;
|
|
@@ -1,44 +1,95 @@
|
|
|
1
|
-
use crate::classes::FileComplexity;
|
|
1
|
+
use crate::classes::{FileComplexity, FunctionComplexity};
|
|
2
2
|
use csv::Writer;
|
|
3
3
|
use pyo3::prelude::*;
|
|
4
4
|
use rustpython_parser::ast::{self, Stmt};
|
|
5
5
|
|
|
6
6
|
#[pyfunction]
|
|
7
|
-
pub fn output_csv_file_level(
|
|
7
|
+
pub fn output_csv_file_level(
|
|
8
|
+
invocation_path: &str,
|
|
9
|
+
files_complexity: Vec<FileComplexity>,
|
|
10
|
+
sort: &str,
|
|
11
|
+
) {
|
|
8
12
|
let mut writer = Writer::from_path(invocation_path).unwrap();
|
|
9
13
|
|
|
10
14
|
writer
|
|
11
15
|
.write_record(&["Path", "File Name", "Cognitive Complexity"])
|
|
12
16
|
.unwrap();
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
if sort != "name" {
|
|
19
|
+
let mut files_complexity = files_complexity;
|
|
20
|
+
|
|
21
|
+
files_complexity.sort_by_key(|f| f.complexity);
|
|
22
|
+
|
|
23
|
+
if sort == "desc" {
|
|
24
|
+
files_complexity.reverse();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
for file in files_complexity.into_iter() {
|
|
28
|
+
writer
|
|
29
|
+
.write_record(&[&file.path, &file.file_name, &file.complexity.to_string()])
|
|
30
|
+
.unwrap();
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
for file in &files_complexity {
|
|
34
|
+
writer
|
|
35
|
+
.write_record(&[&file.path, &file.file_name, &file.complexity.to_string()])
|
|
36
|
+
.unwrap();
|
|
37
|
+
}
|
|
18
38
|
}
|
|
19
39
|
|
|
20
40
|
writer.flush().unwrap();
|
|
21
41
|
}
|
|
22
42
|
|
|
23
43
|
#[pyfunction]
|
|
24
|
-
pub fn output_csv_function_level(
|
|
44
|
+
pub fn output_csv_function_level(
|
|
45
|
+
invocation_path: &str,
|
|
46
|
+
functions_complexity: Vec<FileComplexity>,
|
|
47
|
+
sort: &str,
|
|
48
|
+
) {
|
|
25
49
|
let mut writer = Writer::from_path(invocation_path).unwrap();
|
|
26
50
|
|
|
27
51
|
writer
|
|
28
52
|
.write_record(&["Path", "File Name", "Function Name", "Cognitive Complexity"])
|
|
29
53
|
.unwrap();
|
|
30
54
|
|
|
31
|
-
|
|
32
|
-
|
|
55
|
+
if sort != "name" {
|
|
56
|
+
let mut all_functions: Vec<(String, String, FunctionComplexity)> = vec![];
|
|
57
|
+
|
|
58
|
+
for file in functions_complexity {
|
|
59
|
+
for function in file.functions {
|
|
60
|
+
all_functions.push((file.path.clone(), file.file_name.clone(), function));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
all_functions.sort_by_key(|f| f.2.complexity);
|
|
65
|
+
|
|
66
|
+
if sort == "desc" {
|
|
67
|
+
all_functions.reverse();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
for (path, file_name, function) in all_functions.into_iter() {
|
|
33
71
|
writer
|
|
34
72
|
.write_record(&[
|
|
35
|
-
&
|
|
36
|
-
&
|
|
73
|
+
&path,
|
|
74
|
+
&file_name,
|
|
37
75
|
&function.name,
|
|
38
76
|
&function.complexity.to_string(),
|
|
39
77
|
])
|
|
40
78
|
.unwrap();
|
|
41
79
|
}
|
|
80
|
+
} else {
|
|
81
|
+
for file in functions_complexity {
|
|
82
|
+
for function in file.functions {
|
|
83
|
+
writer
|
|
84
|
+
.write_record(&[
|
|
85
|
+
&file.path,
|
|
86
|
+
&file.file_name,
|
|
87
|
+
&function.name,
|
|
88
|
+
&function.complexity.to_string(),
|
|
89
|
+
])
|
|
90
|
+
.unwrap();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
42
93
|
}
|
|
43
94
|
|
|
44
95
|
writer.flush().unwrap();
|
|
@@ -83,16 +134,13 @@ pub fn count_bool_ops(expr: ast::Expr) -> u64 {
|
|
|
83
134
|
let mut complexity: u64 = 0;
|
|
84
135
|
|
|
85
136
|
match expr {
|
|
86
|
-
ast::Expr::BoolOp(
|
|
87
|
-
complexity += 1;
|
|
88
|
-
}
|
|
89
|
-
ast::Expr::BinOp(b) => {
|
|
137
|
+
ast::Expr::BoolOp(b) => {
|
|
90
138
|
complexity += 1;
|
|
91
|
-
|
|
92
|
-
|
|
139
|
+
for value in b.values.iter() {
|
|
140
|
+
complexity += count_bool_ops(value.clone());
|
|
141
|
+
}
|
|
93
142
|
}
|
|
94
143
|
ast::Expr::UnaryOp(u) => {
|
|
95
|
-
complexity += 1;
|
|
96
144
|
complexity += count_bool_ops(*u.operand);
|
|
97
145
|
}
|
|
98
146
|
ast::Expr::Compare(c) => {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|