codeanalyzer-python 0.1.11__py3-none-any.whl → 0.1.12__py3-none-any.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.
- codeanalyzer/__main__.py +40 -86
- codeanalyzer/core.py +13 -27
- codeanalyzer/options/__init__.py +3 -0
- codeanalyzer/options/options.py +25 -0
- {codeanalyzer_python-0.1.11.dist-info → codeanalyzer_python-0.1.12.dist-info}/METADATA +1 -1
- {codeanalyzer_python-0.1.11.dist-info → codeanalyzer_python-0.1.12.dist-info}/RECORD +10 -8
- {codeanalyzer_python-0.1.11.dist-info → codeanalyzer_python-0.1.12.dist-info}/WHEEL +0 -0
- {codeanalyzer_python-0.1.11.dist-info → codeanalyzer_python-0.1.12.dist-info}/entry_points.txt +0 -0
- {codeanalyzer_python-0.1.11.dist-info → codeanalyzer_python-0.1.12.dist-info}/licenses/LICENSE +0 -0
- {codeanalyzer_python-0.1.11.dist-info → codeanalyzer_python-0.1.12.dist-info}/licenses/NOTICE +0 -0
codeanalyzer/__main__.py
CHANGED
|
@@ -7,107 +7,62 @@ from codeanalyzer.core import Codeanalyzer
|
|
|
7
7
|
from codeanalyzer.utils import _set_log_level, logger
|
|
8
8
|
from codeanalyzer.config import OutputFormat
|
|
9
9
|
from codeanalyzer.schema import model_dump_json
|
|
10
|
+
from codeanalyzer.options import AnalysisOptions
|
|
10
11
|
|
|
11
12
|
def main(
|
|
12
|
-
input: Annotated[
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
help="Output format: json or msgpack.",
|
|
25
|
-
case_sensitive=False,
|
|
26
|
-
),
|
|
27
|
-
] = OutputFormat.JSON,
|
|
28
|
-
analysis_level: Annotated[
|
|
29
|
-
int,
|
|
30
|
-
typer.Option("-a", "--analysis-level", help="1: symbol table, 2: call graph."),
|
|
31
|
-
] = 1,
|
|
32
|
-
using_codeql: Annotated[
|
|
33
|
-
bool, typer.Option("--codeql/--no-codeql", help="Enable CodeQL-based analysis.")
|
|
34
|
-
] = False,
|
|
35
|
-
using_ray: Annotated[
|
|
36
|
-
bool,
|
|
37
|
-
typer.Option(
|
|
38
|
-
"--ray/--no-ray", help="Enable Ray for distributed analysis."
|
|
39
|
-
),
|
|
40
|
-
] = False,
|
|
41
|
-
rebuild_analysis: Annotated[
|
|
42
|
-
bool,
|
|
43
|
-
typer.Option(
|
|
44
|
-
"--eager/--lazy",
|
|
45
|
-
help="Enable eager or lazy analysis. Defaults to lazy.",
|
|
46
|
-
),
|
|
47
|
-
] = False,
|
|
48
|
-
skip_tests: Annotated[
|
|
49
|
-
bool,
|
|
50
|
-
typer.Option(
|
|
51
|
-
"--skip-tests/--include-tests",
|
|
52
|
-
help="Skip test files in analysis.",
|
|
53
|
-
),
|
|
54
|
-
] = True,
|
|
55
|
-
file_name: Annotated[
|
|
56
|
-
Optional[Path],
|
|
57
|
-
typer.Option(
|
|
58
|
-
"--file-name",
|
|
59
|
-
help="Analyze only the specified file (relative to input directory).",
|
|
60
|
-
),
|
|
61
|
-
] = None,
|
|
62
|
-
cache_dir: Annotated[
|
|
63
|
-
Optional[Path],
|
|
64
|
-
typer.Option(
|
|
65
|
-
"-c",
|
|
66
|
-
"--cache-dir",
|
|
67
|
-
help="Directory to store analysis cache. Defaults to '.codeanalyzer' in the input directory.",
|
|
68
|
-
),
|
|
69
|
-
] = None,
|
|
70
|
-
clear_cache: Annotated[
|
|
71
|
-
bool,
|
|
72
|
-
typer.Option("--clear-cache/--keep-cache", help="Clear cache after analysis. By default, cache is retained."),
|
|
73
|
-
] = False,
|
|
74
|
-
verbosity: Annotated[
|
|
75
|
-
int, typer.Option("-v", count=True, help="Increase verbosity: -v, -vv, -vvv")
|
|
76
|
-
] = 0,
|
|
13
|
+
input: Annotated[Path, typer.Option("-i", "--input", help="Path to the project root directory.")],
|
|
14
|
+
output: Optional[Path] = typer.Option(None, "-o", "--output"),
|
|
15
|
+
format: OutputFormat = typer.Option(OutputFormat.JSON, "-f", "--format"),
|
|
16
|
+
analysis_level: int = typer.Option(1, "-a", "--analysis-level"),
|
|
17
|
+
using_codeql: bool = typer.Option(False, "--codeql/--no-codeql"),
|
|
18
|
+
using_ray: bool = typer.Option(False, "--ray/--no-ray"),
|
|
19
|
+
rebuild_analysis: bool = typer.Option(False, "--eager/--lazy"),
|
|
20
|
+
skip_tests: bool = typer.Option(True, "--skip-tests/--include-tests"),
|
|
21
|
+
file_name: Optional[Path] = typer.Option(None, "--file-name"),
|
|
22
|
+
cache_dir: Optional[Path] = typer.Option(None, "-c", "--cache-dir"),
|
|
23
|
+
clear_cache: bool = typer.Option(False, "--clear-cache/--keep-cache"),
|
|
24
|
+
verbosity: int = typer.Option(0, "-v", count=True),
|
|
77
25
|
):
|
|
78
|
-
|
|
79
|
-
|
|
26
|
+
options = AnalysisOptions(
|
|
27
|
+
input=input,
|
|
28
|
+
output=output,
|
|
29
|
+
format=format,
|
|
30
|
+
analysis_level=analysis_level,
|
|
31
|
+
using_codeql=using_codeql,
|
|
32
|
+
using_ray=using_ray,
|
|
33
|
+
rebuild_analysis=rebuild_analysis,
|
|
34
|
+
skip_tests=skip_tests,
|
|
35
|
+
file_name=file_name,
|
|
36
|
+
cache_dir=cache_dir,
|
|
37
|
+
clear_cache=clear_cache,
|
|
38
|
+
verbosity=verbosity,
|
|
39
|
+
)
|
|
80
40
|
|
|
81
|
-
|
|
82
|
-
|
|
41
|
+
_set_log_level(options.verbosity)
|
|
42
|
+
if not options.input.exists():
|
|
43
|
+
logger.error(f"Input path '{options.input}' does not exist.")
|
|
83
44
|
raise typer.Exit(code=1)
|
|
84
45
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
full_file_path = input / file_name
|
|
46
|
+
if options.file_name is not None:
|
|
47
|
+
full_file_path = options.input / options.file_name
|
|
88
48
|
if not full_file_path.exists():
|
|
89
|
-
logger.error(f"Specified file '{file_name}' does not exist in '{input}'.")
|
|
49
|
+
logger.error(f"Specified file '{options.file_name}' does not exist in '{options.input}'.")
|
|
90
50
|
raise typer.Exit(code=1)
|
|
91
51
|
if not full_file_path.is_file():
|
|
92
|
-
logger.error(f"Specified path '{file_name}' is not a file.")
|
|
52
|
+
logger.error(f"Specified path '{options.file_name}' is not a file.")
|
|
93
53
|
raise typer.Exit(code=1)
|
|
94
|
-
if not str(file_name).endswith('.py'):
|
|
95
|
-
logger.error(f"Specified file '{file_name}' is not a Python file (.py).")
|
|
54
|
+
if not str(options.file_name).endswith('.py'):
|
|
55
|
+
logger.error(f"Specified file '{options.file_name}' is not a Python file (.py).")
|
|
96
56
|
raise typer.Exit(code=1)
|
|
97
57
|
|
|
98
|
-
with Codeanalyzer(
|
|
99
|
-
input, analysis_level, skip_tests, using_codeql, rebuild_analysis, cache_dir, clear_cache, using_ray, file_name
|
|
100
|
-
) as analyzer:
|
|
58
|
+
with Codeanalyzer(options) as analyzer:
|
|
101
59
|
artifacts = analyzer.analyze()
|
|
102
60
|
|
|
103
|
-
|
|
104
|
-
if output is None:
|
|
105
|
-
# Output to stdout (only for JSON)
|
|
61
|
+
if options.output is None:
|
|
106
62
|
print(model_dump_json(artifacts, separators=(",", ":")))
|
|
107
63
|
else:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
_write_output(artifacts, output, format)
|
|
64
|
+
options.output.mkdir(parents=True, exist_ok=True)
|
|
65
|
+
_write_output(artifacts, options.output, options.format)
|
|
111
66
|
|
|
112
67
|
|
|
113
68
|
def _write_output(artifacts, output_dir: Path, format: OutputFormat):
|
|
@@ -130,7 +85,6 @@ def _write_output(artifacts, output_dir: Path, format: OutputFormat):
|
|
|
130
85
|
f"Compression ratio: {artifacts.get_compression_ratio():.1%} of JSON size"
|
|
131
86
|
)
|
|
132
87
|
|
|
133
|
-
|
|
134
88
|
app = typer.Typer(
|
|
135
89
|
callback=main,
|
|
136
90
|
name="codeanalyzer",
|
codeanalyzer/core.py
CHANGED
|
@@ -14,6 +14,7 @@ from codeanalyzer.semantic_analysis.codeql.codeql_exceptions import CodeQLExcept
|
|
|
14
14
|
from codeanalyzer.syntactic_analysis.exceptions import SymbolTableBuilderRayError
|
|
15
15
|
from codeanalyzer.syntactic_analysis.symbol_table_builder import SymbolTableBuilder
|
|
16
16
|
from codeanalyzer.utils import ProgressBar
|
|
17
|
+
from codeanalyzer.options import AnalysisOptions
|
|
17
18
|
|
|
18
19
|
@ray.remote
|
|
19
20
|
def _process_file_with_ray(py_file: Union[Path, str], project_dir: Union[Path, str], virtualenv: Union[Path, str, None]) -> Dict[str, PyModule]:
|
|
@@ -43,40 +44,25 @@ class Codeanalyzer:
|
|
|
43
44
|
"""Core functionality for CodeQL analysis.
|
|
44
45
|
|
|
45
46
|
Args:
|
|
46
|
-
|
|
47
|
-
virtualenv (Optional[Path]): Path to the virtual environment directory.
|
|
48
|
-
using_codeql (bool): Whether to use CodeQL for analysis.
|
|
49
|
-
rebuild_analysis (bool): Whether to force rebuild the database.
|
|
50
|
-
clear_cache (bool): Whether to delete the cached directory after analysis.
|
|
51
|
-
analysis_depth (int): Depth of analysis (reserved for future use).
|
|
47
|
+
options (AnalysisOptions): Analysis configuration options containing all necessary parameters.
|
|
52
48
|
"""
|
|
53
49
|
|
|
54
|
-
def __init__(
|
|
55
|
-
self
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
skip_tests
|
|
59
|
-
using_codeql
|
|
60
|
-
rebuild_analysis
|
|
61
|
-
cache_dir: Optional[Path],
|
|
62
|
-
clear_cache: bool,
|
|
63
|
-
using_ray: bool,
|
|
64
|
-
file_name: Optional[Path] = None,
|
|
65
|
-
) -> None:
|
|
66
|
-
self.analysis_depth = analysis_depth
|
|
67
|
-
self.project_dir = Path(project_dir).resolve()
|
|
68
|
-
self.skip_tests = skip_tests
|
|
69
|
-
self.using_codeql = using_codeql
|
|
70
|
-
self.rebuild_analysis = rebuild_analysis
|
|
50
|
+
def __init__(self, options: AnalysisOptions) -> None:
|
|
51
|
+
self.options = options
|
|
52
|
+
self.analysis_depth = options.analysis_level
|
|
53
|
+
self.project_dir = Path(options.input).resolve()
|
|
54
|
+
self.skip_tests = options.skip_tests
|
|
55
|
+
self.using_codeql = options.using_codeql
|
|
56
|
+
self.rebuild_analysis = options.rebuild_analysis
|
|
71
57
|
self.cache_dir = (
|
|
72
|
-
cache_dir.resolve() if cache_dir is not None else self.project_dir
|
|
58
|
+
options.cache_dir.resolve() if options.cache_dir is not None else self.project_dir
|
|
73
59
|
) / ".codeanalyzer"
|
|
74
|
-
self.clear_cache = clear_cache
|
|
60
|
+
self.clear_cache = options.clear_cache
|
|
75
61
|
self.db_path: Optional[Path] = None
|
|
76
62
|
self.codeql_bin: Optional[Path] = None
|
|
77
63
|
self.virtualenv: Optional[Path] = None
|
|
78
|
-
self.using_ray: bool = using_ray
|
|
79
|
-
self.file_name: Optional[Path] = file_name
|
|
64
|
+
self.using_ray: bool = options.using_ray
|
|
65
|
+
self.file_name: Optional[Path] = options.file_name
|
|
80
66
|
|
|
81
67
|
@staticmethod
|
|
82
68
|
def _cmd_exec_helper(
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class OutputFormat(str, Enum):
|
|
8
|
+
JSON = "json"
|
|
9
|
+
MSGPACK = "msgpack"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class AnalysisOptions:
|
|
14
|
+
input: Path
|
|
15
|
+
output: Optional[Path] = None
|
|
16
|
+
format: OutputFormat = OutputFormat.JSON
|
|
17
|
+
analysis_level: int = 1
|
|
18
|
+
using_codeql: bool = False
|
|
19
|
+
using_ray: bool = False
|
|
20
|
+
rebuild_analysis: bool = False
|
|
21
|
+
skip_tests: bool = True
|
|
22
|
+
file_name: Optional[Path] = None
|
|
23
|
+
cache_dir: Optional[Path] = None
|
|
24
|
+
clear_cache: bool = False
|
|
25
|
+
verbosity: int = 0
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
codeanalyzer/__init__.py,sha256=BZ3Kuwl-F_F-8H8cepLnVJ4Ku4NNUjjqg0Y6ujPQSsI,108
|
|
2
|
-
codeanalyzer/__main__.py,sha256=
|
|
3
|
-
codeanalyzer/core.py,sha256=
|
|
2
|
+
codeanalyzer/__main__.py,sha256=DLyvuQXnzwx5wIb2xvLg5qzmzOyvLz4Uxiz_Y8bbfHs,3938
|
|
3
|
+
codeanalyzer/core.py,sha256=P43skGiKUnQtkSQGHpPDgZrftAKP2HHh52g1N1Ww1S0,24503
|
|
4
4
|
codeanalyzer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
codeanalyzer/config/__init__.py,sha256=9XBxAn1oWGRuhg3bEBUuVGs3hFNXEAKrr-Ce7tq9a2k,61
|
|
6
6
|
codeanalyzer/config/config.py,sha256=ZiKzc5uEUCIvih58-6BDtLLI1hPij41wGQjBcj9KNQM,188
|
|
7
7
|
codeanalyzer/jedi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
codeanalyzer/jedi/jedi.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
codeanalyzer/options/__init__.py,sha256=4kkwBiOrGjalrkfFF8EJgfgOtaPtD7HcCYfZgcOgelU,67
|
|
10
|
+
codeanalyzer/options/options.py,sha256=PNdLUCF7kHfscSeeqbV6ZEAu37T1gFoeV9SqJQed7Fw,592
|
|
9
11
|
codeanalyzer/schema/__init__.py,sha256=HB7y4y-49dkEo-H9GREam1_9Cr1N-GF6MYwx9yoU878,1978
|
|
10
12
|
codeanalyzer/schema/py_schema.py,sha256=04K19tDtmg2tPXjwu_8BcmVpenk1ibVwNv6bHWZHOLY,10851
|
|
11
13
|
codeanalyzer/semantic_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -21,9 +23,9 @@ codeanalyzer/syntactic_analysis/symbol_table_builder.py,sha256=0FE_ZdlyP77P1B70Q
|
|
|
21
23
|
codeanalyzer/utils/__init__.py,sha256=hC6VWdR5rerSqBxzu9KQHTASWqwrrYJv-CMDwrTlzkc,137
|
|
22
24
|
codeanalyzer/utils/logging.py,sha256=0vTkGSl5EZN8yhhWa_5Mrn1n_twRCSW53rNwjzQ9RbI,601
|
|
23
25
|
codeanalyzer/utils/progress_bar.py,sha256=ZHJzGiCo5q4dyXq4CtsrJeq9Ip7sD84T3yZjNX7TBys,2443
|
|
24
|
-
codeanalyzer_python-0.1.
|
|
25
|
-
codeanalyzer_python-0.1.
|
|
26
|
-
codeanalyzer_python-0.1.
|
|
27
|
-
codeanalyzer_python-0.1.
|
|
28
|
-
codeanalyzer_python-0.1.
|
|
29
|
-
codeanalyzer_python-0.1.
|
|
26
|
+
codeanalyzer_python-0.1.12.dist-info/METADATA,sha256=6WbhPKR5AWghHHtngmhf2pMNa35-d-C-d_rIRd5AD7E,16283
|
|
27
|
+
codeanalyzer_python-0.1.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
28
|
+
codeanalyzer_python-0.1.12.dist-info/entry_points.txt,sha256=eUrB7Jq5Oav6RblMX_RYfVLSw_h15NbzC3fNSnGsPuM,59
|
|
29
|
+
codeanalyzer_python-0.1.12.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
30
|
+
codeanalyzer_python-0.1.12.dist-info/licenses/NOTICE,sha256=YU0Z9NDWqKY-2jfFcbxeZ6fbnzz0oZeKmnUcO8a-bcQ,901
|
|
31
|
+
codeanalyzer_python-0.1.12.dist-info/RECORD,,
|
|
File without changes
|
{codeanalyzer_python-0.1.11.dist-info → codeanalyzer_python-0.1.12.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{codeanalyzer_python-0.1.11.dist-info → codeanalyzer_python-0.1.12.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{codeanalyzer_python-0.1.11.dist-info → codeanalyzer_python-0.1.12.dist-info}/licenses/NOTICE
RENAMED
|
File without changes
|