complexipy 5.2.0__cp38-cp38-win_amd64.whl
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/__init__.py +21 -0
- complexipy/_complexipy.cp38-win_amd64.pyd +0 -0
- complexipy/_complexipy.pyi +518 -0
- complexipy/api.py +78 -0
- complexipy/main.py +332 -0
- complexipy/py.typed +0 -0
- complexipy/types.py +33 -0
- complexipy/utils/__init__.py +0 -0
- complexipy/utils/cache.py +168 -0
- complexipy/utils/csv.py +19 -0
- complexipy/utils/json.py +17 -0
- complexipy/utils/output.py +237 -0
- complexipy/utils/snapshot.py +125 -0
- complexipy/utils/toml.py +246 -0
- complexipy-5.2.0.dist-info/METADATA +304 -0
- complexipy-5.2.0.dist-info/RECORD +19 -0
- complexipy-5.2.0.dist-info/WHEEL +4 -0
- complexipy-5.2.0.dist-info/entry_points.txt +2 -0
- complexipy-5.2.0.dist-info/licenses/LICENSE +21 -0
complexipy/__init__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from complexipy._complexipy import (
|
|
4
|
+
CodeComplexity,
|
|
5
|
+
FileComplexity,
|
|
6
|
+
FunctionComplexity,
|
|
7
|
+
LineComplexity,
|
|
8
|
+
)
|
|
9
|
+
from complexipy.api import (
|
|
10
|
+
code_complexity,
|
|
11
|
+
file_complexity,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"CodeComplexity",
|
|
16
|
+
"FileComplexity",
|
|
17
|
+
"FunctionComplexity",
|
|
18
|
+
"LineComplexity",
|
|
19
|
+
"code_complexity",
|
|
20
|
+
"file_complexity",
|
|
21
|
+
]
|
|
Binary file
|
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Type stubs for complexipy._complexipy module.
|
|
3
|
+
|
|
4
|
+
This module provides Rust-powered cognitive complexity analysis for Python code.
|
|
5
|
+
Cognitive complexity is a metric that measures how difficult a function is to
|
|
6
|
+
understand and maintain, focusing on control flow structures that make code
|
|
7
|
+
harder to reason about.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from typing import List, Tuple
|
|
11
|
+
|
|
12
|
+
class LineComplexity:
|
|
13
|
+
"""
|
|
14
|
+
Represents the cognitive complexity contribution of a single line of code.
|
|
15
|
+
|
|
16
|
+
Cognitive complexity is incremented by control flow structures like:
|
|
17
|
+
- if/elif statements (+1 each)
|
|
18
|
+
- loops (for/while) (+1 each)
|
|
19
|
+
- except clauses (+1 each)
|
|
20
|
+
- Nested structures (+1 for each level of nesting)
|
|
21
|
+
- Boolean operators in conditions (and/or) (+1 each)
|
|
22
|
+
|
|
23
|
+
This class tracks which specific lines contribute to the overall complexity
|
|
24
|
+
score, helping developers identify the most complex parts of their functions.
|
|
25
|
+
|
|
26
|
+
Example:
|
|
27
|
+
>>> # For a line like: if condition and other_condition:
|
|
28
|
+
>>> line_complexity = LineComplexity(line=5, complexity=2)
|
|
29
|
+
>>> print(f"Line {line_complexity.line} adds {line_complexity.complexity} to complexity")
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
line: int
|
|
33
|
+
"""The line number (1-indexed) in the source code."""
|
|
34
|
+
|
|
35
|
+
complexity: int
|
|
36
|
+
"""
|
|
37
|
+
The cognitive complexity value contributed by this line.
|
|
38
|
+
|
|
39
|
+
- 0: No complexity contribution (simple statements)
|
|
40
|
+
- 1+: Complexity added by control flow structures on this line
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, line: int, complexity: int) -> None: ...
|
|
44
|
+
|
|
45
|
+
class FunctionComplexity:
|
|
46
|
+
"""
|
|
47
|
+
Represents the cognitive complexity analysis of a Python function.
|
|
48
|
+
|
|
49
|
+
This class provides a complete complexity analysis for a single function,
|
|
50
|
+
including the total complexity score and line-by-line breakdown. The
|
|
51
|
+
cognitive complexity score helps assess how difficult a function is to
|
|
52
|
+
understand and maintain.
|
|
53
|
+
|
|
54
|
+
Complexity Guidelines:
|
|
55
|
+
- 1-10: Simple function, easy to understand
|
|
56
|
+
- 11-15: Moderate complexity, consider refactoring
|
|
57
|
+
- 16+: High complexity, should be refactored
|
|
58
|
+
|
|
59
|
+
The analysis includes nested complexity penalties, where deeply nested
|
|
60
|
+
control structures add additional complexity points.
|
|
61
|
+
|
|
62
|
+
Example:
|
|
63
|
+
>>> func = FunctionComplexity(
|
|
64
|
+
... name="process_data",
|
|
65
|
+
... complexity=8,
|
|
66
|
+
... line_start=10,
|
|
67
|
+
... line_end=25,
|
|
68
|
+
... line_complexities=[LineComplexity(12, 2), LineComplexity(15, 1)]
|
|
69
|
+
... )
|
|
70
|
+
>>> print(f"Function '{func.name}' has complexity {func.complexity}")
|
|
71
|
+
>>> # Find the most complex lines
|
|
72
|
+
>>> complex_lines = [lc for lc in func.line_complexities if lc.complexity > 0]
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
name: str
|
|
76
|
+
"""
|
|
77
|
+
The name of the function as it appears in the source code.
|
|
78
|
+
|
|
79
|
+
For methods, this includes just the method name (not the class).
|
|
80
|
+
For nested functions, this is the inner function name.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
complexity: int
|
|
84
|
+
"""
|
|
85
|
+
The total cognitive complexity score for this function.
|
|
86
|
+
|
|
87
|
+
This is the sum of all complexity contributions from control flow
|
|
88
|
+
structures within the function, including nesting penalties.
|
|
89
|
+
Higher values indicate more complex, harder-to-understand code.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
line_start: int
|
|
93
|
+
"""
|
|
94
|
+
The starting line number of the function definition (1-indexed).
|
|
95
|
+
|
|
96
|
+
Points to the line containing 'def function_name(...):'
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
line_end: int
|
|
100
|
+
"""
|
|
101
|
+
The ending line number of the function definition (1-indexed).
|
|
102
|
+
|
|
103
|
+
Points to the last line that belongs to this function's body.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
line_complexities: List[LineComplexity]
|
|
107
|
+
"""
|
|
108
|
+
Detailed complexity information for each line in the function.
|
|
109
|
+
|
|
110
|
+
This list contains LineComplexity objects for every line in the function,
|
|
111
|
+
allowing you to identify exactly which lines contribute to the overall
|
|
112
|
+
complexity score. Lines with zero complexity are included for completeness.
|
|
113
|
+
|
|
114
|
+
Example:
|
|
115
|
+
>>> # Find lines that add complexity
|
|
116
|
+
>>> complex_lines = [lc for lc in func.line_complexities if lc.complexity > 0]
|
|
117
|
+
>>> for line_info in complex_lines:
|
|
118
|
+
... print(f"Line {line_info.line}: +{line_info.complexity}")
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
def __init__(
|
|
122
|
+
self,
|
|
123
|
+
name: str,
|
|
124
|
+
complexity: int,
|
|
125
|
+
line_start: int,
|
|
126
|
+
line_end: int,
|
|
127
|
+
line_complexities: List[LineComplexity],
|
|
128
|
+
) -> None: ...
|
|
129
|
+
|
|
130
|
+
class FileComplexity:
|
|
131
|
+
"""
|
|
132
|
+
Represents the cognitive complexity analysis of a Python source file.
|
|
133
|
+
|
|
134
|
+
This class aggregates complexity information for all functions found in a
|
|
135
|
+
Python file, providing both individual function analysis and file-level
|
|
136
|
+
metrics. It's useful for understanding the overall complexity of a module
|
|
137
|
+
and identifying which functions need attention.
|
|
138
|
+
|
|
139
|
+
File Complexity Guidelines:
|
|
140
|
+
- Low: Most functions have complexity < 10
|
|
141
|
+
- Medium: Some functions have complexity 10-15
|
|
142
|
+
- High: Multiple functions have complexity > 15
|
|
143
|
+
|
|
144
|
+
The file complexity is the sum of all function complexities, helping
|
|
145
|
+
identify files that may be doing too much or need to be split up.
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
>>> file_analysis = FileComplexity(
|
|
149
|
+
... path="/path/to/mymodule.py",
|
|
150
|
+
... file_name="mymodule.py",
|
|
151
|
+
... functions=[func1, func2, func3],
|
|
152
|
+
... complexity=25
|
|
153
|
+
... )
|
|
154
|
+
>>> # Find the most complex functions
|
|
155
|
+
>>> complex_funcs = [f for f in file_analysis.functions if f.complexity > 10]
|
|
156
|
+
>>> print(f"File has {len(complex_funcs)} complex functions")
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
path: str
|
|
160
|
+
"""
|
|
161
|
+
The absolute file path to the analyzed Python file.
|
|
162
|
+
|
|
163
|
+
This is the complete path as resolved by the system, useful for
|
|
164
|
+
identifying the exact location of the file in the filesystem.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
file_name: str
|
|
168
|
+
"""
|
|
169
|
+
The basename of the file (filename without directory path).
|
|
170
|
+
|
|
171
|
+
Example: For "/path/to/mymodule.py", this would be "mymodule.py"
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
functions: List[FunctionComplexity]
|
|
175
|
+
"""
|
|
176
|
+
List of complexity analysis results for each function in the file.
|
|
177
|
+
|
|
178
|
+
This includes all top-level functions and methods found in the file.
|
|
179
|
+
Nested functions are analyzed as part of their containing function.
|
|
180
|
+
The list is ordered by appearance in the source code.
|
|
181
|
+
|
|
182
|
+
Example:
|
|
183
|
+
>>> # Find the most complex function
|
|
184
|
+
>>> most_complex = max(file_analysis.functions, key=lambda f: f.complexity)
|
|
185
|
+
>>> print(f"Most complex function: {most_complex.name} ({most_complex.complexity})")
|
|
186
|
+
|
|
187
|
+
>>> # Get functions that exceed threshold
|
|
188
|
+
>>> threshold = 15
|
|
189
|
+
>>> problematic = [f for f in file_analysis.functions if f.complexity > threshold]
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
complexity: int
|
|
193
|
+
"""
|
|
194
|
+
The total cognitive complexity of the entire file.
|
|
195
|
+
|
|
196
|
+
This is calculated as the sum of complexity scores from all functions
|
|
197
|
+
in the file. It provides a high-level metric for the overall complexity
|
|
198
|
+
of the module and can help identify files that need refactoring.
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
def __init__(
|
|
202
|
+
self,
|
|
203
|
+
path: str,
|
|
204
|
+
file_name: str,
|
|
205
|
+
functions: List[FunctionComplexity],
|
|
206
|
+
complexity: int,
|
|
207
|
+
) -> None: ...
|
|
208
|
+
|
|
209
|
+
class CodeComplexity:
|
|
210
|
+
"""
|
|
211
|
+
Represents the cognitive complexity analysis of a Python code string.
|
|
212
|
+
|
|
213
|
+
This class is used when analyzing Python code provided as a string rather
|
|
214
|
+
than from a file. It's particularly useful for:
|
|
215
|
+
- Analyzing code snippets or templates
|
|
216
|
+
- Testing complexity in unit tests
|
|
217
|
+
- Analyzing dynamically generated code
|
|
218
|
+
- Integration with code editors and IDEs
|
|
219
|
+
|
|
220
|
+
The analysis works identically to file-based analysis, parsing the code
|
|
221
|
+
string to identify functions and calculate their complexity scores.
|
|
222
|
+
|
|
223
|
+
Example:
|
|
224
|
+
>>> code = '''
|
|
225
|
+
... def complex_function(x, y):
|
|
226
|
+
... if x > 0:
|
|
227
|
+
... for i in range(y):
|
|
228
|
+
... if i % 2 == 0 and i > 5:
|
|
229
|
+
... return i * x
|
|
230
|
+
... return 0
|
|
231
|
+
... '''
|
|
232
|
+
>>> analysis = code_complexity(code)
|
|
233
|
+
>>> print(f"Code has {len(analysis.functions)} functions")
|
|
234
|
+
>>> print(f"Total complexity: {analysis.complexity}")
|
|
235
|
+
"""
|
|
236
|
+
|
|
237
|
+
functions: List[FunctionComplexity]
|
|
238
|
+
"""
|
|
239
|
+
List of complexity analysis results for each function found in the code.
|
|
240
|
+
|
|
241
|
+
This includes all function definitions found in the provided code string,
|
|
242
|
+
analyzed in the same way as file-based analysis. Functions are ordered
|
|
243
|
+
by their appearance in the code.
|
|
244
|
+
|
|
245
|
+
Example:
|
|
246
|
+
>>> for func in analysis.functions:
|
|
247
|
+
... print(f"Function '{func.name}': complexity {func.complexity}")
|
|
248
|
+
... if func.complexity > 10:
|
|
249
|
+
... print(" -> Consider refactoring this function")
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
complexity: int
|
|
253
|
+
"""
|
|
254
|
+
The total cognitive complexity of all functions in the code string.
|
|
255
|
+
|
|
256
|
+
This is the sum of complexity scores from all functions found in the
|
|
257
|
+
provided code. It gives an overall measure of how complex the code is.
|
|
258
|
+
"""
|
|
259
|
+
|
|
260
|
+
def __init__(
|
|
261
|
+
self, functions: List[FunctionComplexity], complexity: int
|
|
262
|
+
) -> None: ...
|
|
263
|
+
|
|
264
|
+
def main(
|
|
265
|
+
paths: List[str], quiet: bool, exclude: List[str]
|
|
266
|
+
) -> Tuple[List[FileComplexity], List[str]]:
|
|
267
|
+
"""
|
|
268
|
+
Analyze cognitive complexity of Python files and directories.
|
|
269
|
+
|
|
270
|
+
This is the main analysis function that processes multiple paths, which can
|
|
271
|
+
be individual Python files, directories containing Python files, or Git
|
|
272
|
+
repository URLs. It recursively analyzes all Python files found.
|
|
273
|
+
|
|
274
|
+
The function handles various input types:
|
|
275
|
+
- Local Python files: '/path/to/file.py'
|
|
276
|
+
- Local directories: '/path/to/project/' (analyzes all .py files)
|
|
277
|
+
- Git repositories: 'https://github.com/user/repo.git'
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
paths: List of file paths, directory paths, or Git repository URLs to analyze.
|
|
281
|
+
Each path is processed independently and all results are combined.
|
|
282
|
+
quiet: If True, suppresses console output during analysis. Useful for
|
|
283
|
+
programmatic usage where you only want the returned data.
|
|
284
|
+
exclude: List of file paths, directory paths.
|
|
285
|
+
Each path will be excluded from the analysis.
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
List of FileComplexity objects, one for each Python file analyzed.
|
|
289
|
+
Files are ordered by discovery order during filesystem traversal.
|
|
290
|
+
|
|
291
|
+
Raises:
|
|
292
|
+
Various exceptions may be raised for invalid paths, permission errors,
|
|
293
|
+
or Git repository access issues.
|
|
294
|
+
|
|
295
|
+
Example:
|
|
296
|
+
>>> # Analyze a single file
|
|
297
|
+
>>> results = main(['/path/to/script.py'], quiet=True)
|
|
298
|
+
>>>
|
|
299
|
+
>>> # Analyze entire project directory
|
|
300
|
+
>>> results = main(['/path/to/project/'], quiet=False)
|
|
301
|
+
>>>
|
|
302
|
+
>>> # Find files with high complexity
|
|
303
|
+
>>> complex_files = [f for f in results if f.complexity > 50]
|
|
304
|
+
"""
|
|
305
|
+
...
|
|
306
|
+
|
|
307
|
+
def code_complexity(code: str) -> CodeComplexity:
|
|
308
|
+
"""
|
|
309
|
+
Analyze cognitive complexity of Python code provided as a string.
|
|
310
|
+
|
|
311
|
+
This function parses and analyzes Python source code from a string,
|
|
312
|
+
identifying all function definitions and calculating their cognitive
|
|
313
|
+
complexity scores. It's ideal for analyzing code snippets, templates,
|
|
314
|
+
or dynamically generated code.
|
|
315
|
+
|
|
316
|
+
The analysis follows the same cognitive complexity rules as file-based
|
|
317
|
+
analysis, measuring control flow structures and nesting levels that
|
|
318
|
+
make code harder to understand.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
code: A string containing valid Python source code. The code should
|
|
322
|
+
be properly formatted and syntactically correct. Syntax errors
|
|
323
|
+
will cause the analysis to fail.
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
CodeComplexity object containing the analysis results, including
|
|
327
|
+
individual function complexity scores and total complexity.
|
|
328
|
+
|
|
329
|
+
Raises:
|
|
330
|
+
SyntaxError: If the provided code string contains invalid Python syntax.
|
|
331
|
+
|
|
332
|
+
Example:
|
|
333
|
+
>>> code_sample = '''
|
|
334
|
+
... def fibonacci(n):
|
|
335
|
+
... if n <= 1:
|
|
336
|
+
... return n
|
|
337
|
+
... elif n == 2:
|
|
338
|
+
... return 1
|
|
339
|
+
... else:
|
|
340
|
+
... return fibonacci(n-1) + fibonacci(n-2)
|
|
341
|
+
...
|
|
342
|
+
... def factorial(n):
|
|
343
|
+
... result = 1
|
|
344
|
+
... for i in range(1, n + 1):
|
|
345
|
+
... result *= i
|
|
346
|
+
... return result
|
|
347
|
+
... '''
|
|
348
|
+
>>> analysis = code_complexity(code_sample)
|
|
349
|
+
>>> print(f"Found {len(analysis.functions)} functions")
|
|
350
|
+
>>> print(f"Total complexity: {analysis.complexity}")
|
|
351
|
+
>>>
|
|
352
|
+
>>> # Analyze each function
|
|
353
|
+
>>> for func in analysis.functions:
|
|
354
|
+
... print(f"{func.name}: complexity {func.complexity}")
|
|
355
|
+
"""
|
|
356
|
+
...
|
|
357
|
+
|
|
358
|
+
def file_complexity(file_path: str, base_path: str) -> FileComplexity:
|
|
359
|
+
"""
|
|
360
|
+
Analyze cognitive complexity of a single Python source file.
|
|
361
|
+
|
|
362
|
+
This function reads and analyzes a Python file from the filesystem,
|
|
363
|
+
identifying all function definitions and calculating their cognitive
|
|
364
|
+
complexity scores. It's useful for analyzing individual files or
|
|
365
|
+
integrating complexity analysis into custom tools.
|
|
366
|
+
|
|
367
|
+
The function handles file reading, parsing, and complexity calculation,
|
|
368
|
+
providing detailed results for all functions found in the file.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
file_path: Absolute path to the Python file to analyze. The file
|
|
372
|
+
must exist and be readable. Should point to a .py file
|
|
373
|
+
containing valid Python source code.
|
|
374
|
+
base_path: Base directory path used for calculating relative paths
|
|
375
|
+
in the analysis results. This is typically the project
|
|
376
|
+
root directory and affects the 'path' field in the
|
|
377
|
+
returned FileComplexity object.
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
FileComplexity object containing complete analysis results for the
|
|
381
|
+
file, including all functions found and their complexity scores.
|
|
382
|
+
|
|
383
|
+
Raises:
|
|
384
|
+
FileNotFoundError: If the specified file_path does not exist.
|
|
385
|
+
PermissionError: If the file cannot be read due to permissions.
|
|
386
|
+
SyntaxError: If the Python file contains syntax errors.
|
|
387
|
+
UnicodeDecodeError: If the file cannot be decoded as text.
|
|
388
|
+
|
|
389
|
+
Example:
|
|
390
|
+
>>> # Analyze a specific file
|
|
391
|
+
>>> result = file_complexity(
|
|
392
|
+
... file_path="/project/src/mymodule.py",
|
|
393
|
+
... base_path="/project"
|
|
394
|
+
... )
|
|
395
|
+
>>> print(f"File: {result.file_name}")
|
|
396
|
+
>>> print(f"Total complexity: {result.complexity}")
|
|
397
|
+
>>> print(f"Functions analyzed: {len(result.functions)}")
|
|
398
|
+
>>>
|
|
399
|
+
>>> # Find the most complex function
|
|
400
|
+
>>> if result.functions:
|
|
401
|
+
... most_complex = max(result.functions, key=lambda f: f.complexity)
|
|
402
|
+
... print(f"Most complex: {most_complex.name} (score: {most_complex.complexity})")
|
|
403
|
+
"""
|
|
404
|
+
...
|
|
405
|
+
|
|
406
|
+
def output_csv(
|
|
407
|
+
output_path: str,
|
|
408
|
+
files_complexities: List[FileComplexity],
|
|
409
|
+
sort: str,
|
|
410
|
+
show_details: bool,
|
|
411
|
+
max_complexity: int,
|
|
412
|
+
) -> None:
|
|
413
|
+
"""
|
|
414
|
+
Export complexity analysis results to a CSV file for reporting and analysis.
|
|
415
|
+
|
|
416
|
+
This function creates a CSV file containing complexity metrics that can be
|
|
417
|
+
imported into spreadsheet applications, data analysis tools, or used for
|
|
418
|
+
automated reporting. The CSV format makes it easy to track complexity
|
|
419
|
+
trends over time or compare different codebases.
|
|
420
|
+
|
|
421
|
+
The CSV includes columns for file paths, function names, complexity scores,
|
|
422
|
+
line numbers, and other relevant metrics. The level of detail depends on
|
|
423
|
+
the show_details parameter.
|
|
424
|
+
|
|
425
|
+
Args:
|
|
426
|
+
output_path: File system path where the CSV file will be written.
|
|
427
|
+
If the file exists, it will be overwritten. The directory
|
|
428
|
+
must exist and be writable.
|
|
429
|
+
files_complexities: List of FileComplexity objects from analysis
|
|
430
|
+
results. Each file's functions will be included
|
|
431
|
+
in the CSV output.
|
|
432
|
+
sort: Sort order for the results in the CSV file. Valid options:
|
|
433
|
+
- 'asc': Sort by complexity score (ascending, lowest first)
|
|
434
|
+
- 'desc': Sort by complexity score (descending, highest first)
|
|
435
|
+
- 'name': Sort alphabetically by function name
|
|
436
|
+
show_details: If True, includes detailed per-function information.
|
|
437
|
+
If False, only includes summary information.
|
|
438
|
+
max_complexity: Functions with complexity above this threshold will
|
|
439
|
+
be highlighted or filtered in the output. Use 0 to
|
|
440
|
+
include all functions regardless of complexity.
|
|
441
|
+
|
|
442
|
+
Raises:
|
|
443
|
+
PermissionError: If the output path is not writable.
|
|
444
|
+
FileNotFoundError: If the output directory does not exist.
|
|
445
|
+
|
|
446
|
+
Example:
|
|
447
|
+
>>> results = main(['/path/to/project'], quiet=True)
|
|
448
|
+
>>> output_csv(
|
|
449
|
+
... output_path='/tmp/complexity_report.csv',
|
|
450
|
+
... files_complexities=results,
|
|
451
|
+
... sort='desc',
|
|
452
|
+
... show_details=True,
|
|
453
|
+
... max_complexity=15
|
|
454
|
+
... )
|
|
455
|
+
>>> print("CSV report generated successfully")
|
|
456
|
+
"""
|
|
457
|
+
...
|
|
458
|
+
|
|
459
|
+
def output_json(
|
|
460
|
+
output_path: str,
|
|
461
|
+
files_complexities: List[FileComplexity],
|
|
462
|
+
show_details: bool,
|
|
463
|
+
max_complexity: int,
|
|
464
|
+
) -> None:
|
|
465
|
+
"""
|
|
466
|
+
Export complexity analysis results to a JSON file for programmatic consumption.
|
|
467
|
+
|
|
468
|
+
This function serializes complexity analysis results into a structured JSON
|
|
469
|
+
format that can be easily consumed by other tools, CI/CD pipelines, or
|
|
470
|
+
custom applications. The JSON format preserves the full hierarchy of
|
|
471
|
+
files, functions, and line-by-line complexity information.
|
|
472
|
+
|
|
473
|
+
The JSON output is machine-readable and perfect for integration with
|
|
474
|
+
automated quality gates, dashboards, or further data processing. It
|
|
475
|
+
maintains all the detailed information from the analysis.
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
output_path: File system path where the JSON file will be written.
|
|
479
|
+
If the file exists, it will be overwritten. The directory
|
|
480
|
+
must exist and be writable.
|
|
481
|
+
files_complexities: List of FileComplexity objects from analysis
|
|
482
|
+
results. The complete structure will be serialized
|
|
483
|
+
to JSON, preserving all nested information.
|
|
484
|
+
show_details: If True, includes detailed line-by-line complexity
|
|
485
|
+
information for each function. If False, only includes
|
|
486
|
+
summary metrics for better performance and smaller files.
|
|
487
|
+
max_complexity: Functions with complexity above this threshold may
|
|
488
|
+
be flagged or filtered in the output. Use 0 to include
|
|
489
|
+
all functions regardless of complexity.
|
|
490
|
+
|
|
491
|
+
Raises:
|
|
492
|
+
PermissionError: If the output path is not writable.
|
|
493
|
+
FileNotFoundError: If the output directory does not exist.
|
|
494
|
+
JSONEncodeError: If the data cannot be serialized to JSON.
|
|
495
|
+
|
|
496
|
+
Example:
|
|
497
|
+
>>> results = main(['/path/to/project'], quiet=True)
|
|
498
|
+
>>> output_json(
|
|
499
|
+
... output_path='/tmp/complexity_report.json',
|
|
500
|
+
... files_complexities=results,
|
|
501
|
+
... show_details=True,
|
|
502
|
+
... max_complexity=0
|
|
503
|
+
... )
|
|
504
|
+
>>>
|
|
505
|
+
>>> # The JSON can be loaded by other tools
|
|
506
|
+
>>> import json
|
|
507
|
+
>>> with open('/tmp/complexity_report.json') as f:
|
|
508
|
+
... data = json.load(f)
|
|
509
|
+
>>> print(f"Analyzed {len(data)} files")
|
|
510
|
+
"""
|
|
511
|
+
...
|
|
512
|
+
|
|
513
|
+
def create_snapshot_file(
|
|
514
|
+
snapshot_file_path: str,
|
|
515
|
+
max_complexity_allowed: int,
|
|
516
|
+
files_complexities: List[FileComplexity],
|
|
517
|
+
) -> None: ...
|
|
518
|
+
def load_snapshot_file(snapshot_file_path: str) -> List[FileComplexity]: ...
|
complexipy/api.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from complexipy import _complexipy
|
|
4
|
+
from complexipy._complexipy import CodeComplexity, FileComplexity
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def code_complexity(
|
|
8
|
+
code: str,
|
|
9
|
+
) -> CodeComplexity:
|
|
10
|
+
"""
|
|
11
|
+
Analyze cognitive complexity of Python code provided as a string.
|
|
12
|
+
|
|
13
|
+
This function parses and analyzes Python source code from a string,
|
|
14
|
+
identifying all function definitions and calculating their cognitive
|
|
15
|
+
complexity scores. Perfect for analyzing code snippets, templates,
|
|
16
|
+
or dynamically generated code.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
code: A string containing valid Python source code. Must be
|
|
20
|
+
syntactically correct Python code.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
CodeComplexity object containing the analysis results, including
|
|
24
|
+
individual function complexity scores and total complexity.
|
|
25
|
+
|
|
26
|
+
Raises:
|
|
27
|
+
SyntaxError: If the provided code string contains invalid Python syntax.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
>>> code = '''
|
|
31
|
+
... def fibonacci(n):
|
|
32
|
+
... if n <= 1:
|
|
33
|
+
... return n
|
|
34
|
+
... else:
|
|
35
|
+
... return fibonacci(n-1) + fibonacci(n-2)
|
|
36
|
+
... '''
|
|
37
|
+
>>> result = code_complexity(code)
|
|
38
|
+
>>> print(f"Total complexity: {result.complexity}")
|
|
39
|
+
"""
|
|
40
|
+
return _complexipy.code_complexity(code)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def file_complexity(file_path: str) -> FileComplexity:
|
|
44
|
+
"""
|
|
45
|
+
Analyze cognitive complexity of a single Python source file.
|
|
46
|
+
|
|
47
|
+
This function reads and analyzes a Python file from the filesystem,
|
|
48
|
+
identifying all function definitions and calculating their cognitive
|
|
49
|
+
complexity scores. Useful for analyzing individual files or integrating
|
|
50
|
+
complexity analysis into custom tools.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
file_path: Path to the Python file to analyze. Can be relative or
|
|
54
|
+
absolute. The file must exist and be readable.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
FileComplexity object containing complete analysis results for the
|
|
58
|
+
file, including all functions found and their complexity scores.
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
FileNotFoundError: If the specified file does not exist.
|
|
62
|
+
PermissionError: If the file cannot be read due to permissions.
|
|
63
|
+
SyntaxError: If the Python file contains syntax errors.
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
>>> result = file_complexity('mymodule.py')
|
|
67
|
+
>>> print(f"File: {result.file_name}")
|
|
68
|
+
>>> print(f"Total complexity: {result.complexity}")
|
|
69
|
+
>>> for func in result.functions:
|
|
70
|
+
... if func.complexity > 10:
|
|
71
|
+
... print(f"Complex function: {func.name} ({func.complexity})")
|
|
72
|
+
"""
|
|
73
|
+
path = Path(file_path)
|
|
74
|
+
base_path = path.parent
|
|
75
|
+
return _complexipy.file_complexity(
|
|
76
|
+
path.resolve().as_posix(),
|
|
77
|
+
base_path.resolve().as_posix(),
|
|
78
|
+
)
|