codeanalyzer-python 0.1.2__tar.gz → 0.1.4__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.
Files changed (26) hide show
  1. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/.gitignore +4 -1
  2. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/PKG-INFO +48 -40
  3. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/README.md +45 -35
  4. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/__main__.py +51 -13
  5. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/core.py +5 -12
  6. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/schema/__init__.py +6 -6
  7. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/schema/py_schema.py +103 -125
  8. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/semantic_analysis/codeql/codeql_analysis.py +2 -2
  9. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/semantic_analysis/codeql/codeql_loader.py +3 -14
  10. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/semantic_analysis/codeql/codeql_query_runner.py +2 -1
  11. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/syntactic_analysis/symbol_table_builder.py +157 -159
  12. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/utils/__init__.py +1 -2
  13. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/utils/logging.py +2 -1
  14. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/utils/progress_bar.py +5 -4
  15. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/pyproject.toml +4 -5
  16. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/LICENSE +0 -0
  17. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/NOTICE +0 -0
  18. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/__init__.py +0 -0
  19. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/jedi/__init__.py +0 -0
  20. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/jedi/jedi.py +0 -0
  21. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/py.typed +0 -0
  22. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/semantic_analysis/__init__.py +0 -0
  23. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/semantic_analysis/codeql/__init__.py +2 -2
  24. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/semantic_analysis/codeql/codeql_exceptions.py +0 -0
  25. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/semantic_analysis/wala/__init__.py +0 -0
  26. {codeanalyzer_python-0.1.2 → codeanalyzer_python-0.1.4}/codeanalyzer/syntactic_analysis/__init__.py +0 -0
@@ -175,4 +175,7 @@ cython_debug/
175
175
 
176
176
  # Project-specific files
177
177
  .codeanalyzer
178
- .vscode/
178
+ .vscode/
179
+
180
+ # UV
181
+ uv.lock
@@ -1,42 +1,38 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeanalyzer-python
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Static Analysis on Python source code using Jedi, CodeQL and Treesitter.
5
5
  Author-email: Rahul Krishna <i.m.ralk@gmail.com>
6
6
  License-File: LICENSE
7
7
  License-File: NOTICE
8
8
  Requires-Python: >=3.12
9
- Requires-Dist: asteroid>=0.7.0
10
9
  Requires-Dist: astor>=0.8.1
11
10
  Requires-Dist: jedi>=0.19.2
12
11
  Requires-Dist: loguru>=0.7.3
12
+ Requires-Dist: msgpack>=1.1.1
13
13
  Requires-Dist: networkx>=3.5
14
- Requires-Dist: pandas>=2.3.0
14
+ Requires-Dist: pandas>=2.3.1
15
15
  Requires-Dist: pydantic>=2.11.7
16
16
  Requires-Dist: requests>=2.32.4
17
17
  Requires-Dist: rich>=14.0.0
18
- Requires-Dist: ruff>=0.12.2
19
- Requires-Dist: toml>=0.10.2
20
18
  Requires-Dist: typer>=0.16.0
21
19
  Description-Content-Type: text/markdown
22
20
 
23
- ![logo](./docs/assets/logo.png)
21
+ ![logo](https://github.com/codellm-devkit/codeanalyzer-python/blob/main/docs/assets/logo.png?raw=true)
24
22
 
25
- Python Static Analysis Backend for CLDK
23
+ # A Python Static Analysis Toolkit (and Library)
26
24
 
27
25
  A comprehensive static analysis tool for Python source code that provides symbol table generation, call graph analysis, and semantic analysis using Jedi, CodeQL, and Tree-sitter.
28
26
 
29
27
  ## Installation
30
28
 
31
- This project uses [uv](https://docs.astral.sh/uv/) for dependency management.
29
+ ```bash
30
+ pip install codeanalyzer-python
31
+ ```
32
32
 
33
33
  ### Prerequisites
34
34
 
35
- - [uv](https://docs.astral.sh/uv/getting-started/installation/) installed
36
- - Python 3.12 or higher. You can use `uv` to install Python if it's not already installed:
37
- ```bash
38
- uv python install 3.12
39
- ```
35
+ - Python 3.12 or higher
40
36
 
41
37
  #### System Package Requirements
42
38
 
@@ -78,20 +74,6 @@ pyenv global 3.12.0 # or pyenv local 3.12.0 for project-specific
78
74
 
79
75
  > **Note:** These packages are required as the tool uses Python's built-in `venv` module to create isolated environments for analysis.
80
76
 
81
- ### Setup
82
-
83
- 1. Clone the repository:
84
- ```bash
85
- git clone https://github.com/codellm-devkit/codeanalyzer-python
86
- cd codeanalyzer-python
87
- ```
88
-
89
- 2. Install dependencies using uv:
90
- ```bash
91
- uv sync --all-groups
92
- ```
93
- This will install all dependencies including development and test dependencies.
94
-
95
77
  ## Usage
96
78
 
97
79
  The codeanalyzer provides a command-line interface for performing static analysis on Python projects.
@@ -99,15 +81,15 @@ The codeanalyzer provides a command-line interface for performing static analysi
99
81
  ### Basic Usage
100
82
 
101
83
  ```bash
102
- uv run codeanalyzer --input /path/to/python/project
84
+ codeanalyzer --input /path/to/python/project
103
85
  ```
104
86
 
105
87
  ### Command Line Options
106
88
 
107
- To view the available options and commands, run `uv run codeanalyzer --help`. You should see output similar to the following:
89
+ To view the available options and commands, run `codeanalyzer --help`. You should see output similar to the following:
108
90
 
109
91
  ```bash
110
- uv run codeanalyzer --help
92
+ ❯ codeanalyzer --help
111
93
 
112
94
  Usage: codeanalyzer [OPTIONS] COMMAND [ARGS]...
113
95
 
@@ -131,38 +113,38 @@ To view the available options and commands, run `uv run codeanalyzer --help`. Yo
131
113
 
132
114
  1. **Basic analysis with symbol table:**
133
115
  ```bash
134
- uv run codeanalyzer --input ./my-python-project
116
+ codeanalyzer --input ./my-python-project
135
117
  ```
136
118
 
137
119
  This will print the symbol table to stdout in JSON format to the standard output. If you want to save the output, you can use the `--output` option.
138
120
 
139
121
  ```bash
140
- uv run codeanalyzer --input ./my-python-project --output /path/to/analysis-results
122
+ codeanalyzer --input ./my-python-project --output /path/to/analysis-results
141
123
  ```
142
124
 
143
125
  Now, you can find the analysis results in `analysis.json` in the specified directory.
144
126
 
145
127
  2. **Toggle analysis levels with `--analysis-level`:**
146
128
  ```bash
147
- uv run codeanalyzer --input ./my-python-project --analysis-level 1 # Symbol table only
129
+ codeanalyzer --input ./my-python-project --analysis-level 1 # Symbol table only
148
130
  ```
149
131
  Call graph analysis can be enabled by setting the level to `2`:
150
132
  ```bash
151
- uv run codeanalyzer --input ./my-python-project --analysis-level 2 # Symbol table + Call graph
133
+ codeanalyzer --input ./my-python-project --analysis-level 2 # Symbol table + Call graph
152
134
  ```
153
135
  ***Note: The `--analysis-level=2` is not yet implemented in this version.***
154
136
 
155
137
  3. **Analysis with CodeQL enabled:**
156
138
  ```bash
157
- uv run codeanalyzer --input ./my-python-project --codeql
139
+ codeanalyzer --input ./my-python-project --codeql
158
140
  ```
159
- This will perform CodeQL-based analysis in addition to the standard symbol table generation.
160
-
141
+ This will perform CodeQL-based analysis in addition to the standard symbol table generation.
142
+
161
143
  ***Note: Not yet fully implemented. Please refrain from using this option until further notice.***
162
144
 
163
145
  4. **Eager analysis with custom cache directory:**
164
146
  ```bash
165
- uv run codeanalyzer --input ./my-python-project --eager --cache-dir /path/to/custom-cache
147
+ codeanalyzer --input ./my-python-project --eager --cache-dir /path/to/custom-cache
166
148
  ```
167
149
  This will rebuild the analysis cache at every run and store it in `/path/to/custom-cache/.codeanalyzer`. The cache will be cleared by default after analysis unless you specify `--keep-cache`.
168
150
 
@@ -170,7 +152,7 @@ To view the available options and commands, run `uv run codeanalyzer --help`. Yo
170
152
 
171
153
  5. **Quiet mode (minimal output):**
172
154
  ```bash
173
- uv run codeanalyzer --input /path/to/my-python-project --quiet
155
+ codeanalyzer --input /path/to/my-python-project --quiet
174
156
  ```
175
157
 
176
158
  ### Output
@@ -179,10 +161,36 @@ By default, analysis results are printed to stdout in JSON format. When using th
179
161
 
180
162
  ## Development
181
163
 
164
+ This project uses [uv](https://docs.astral.sh/uv/) for dependency management during development.
165
+
166
+ ### Development Setup
167
+
168
+ 1. Install [uv](https://docs.astral.sh/uv/getting-started/installation/)
169
+
170
+ 2. Clone the repository:
171
+ ```bash
172
+ git clone https://github.com/codellm-devkit/codeanalyzer-python
173
+ cd codeanalyzer-python
174
+ ```
175
+
176
+ 3. Install dependencies using uv:
177
+ ```bash
178
+ uv sync --all-groups
179
+ ```
180
+ This will install all dependencies including development and test dependencies.
181
+
182
+ ### Running from Source
183
+
184
+ When developing, you can run the tool directly from source:
185
+
186
+ ```bash
187
+ uv run codeanalyzer --input /path/to/python/project
188
+ ```
189
+
182
190
  ### Running Tests
183
191
 
184
192
  ```bash
185
- uv run pytest --pspec -s
193
+ uv run pytest --pspec -s
186
194
  ```
187
195
 
188
196
  ### Development Dependencies
@@ -1,20 +1,18 @@
1
- ![logo](./docs/assets/logo.png)
1
+ ![logo](https://github.com/codellm-devkit/codeanalyzer-python/blob/main/docs/assets/logo.png?raw=true)
2
2
 
3
- Python Static Analysis Backend for CLDK
3
+ # A Python Static Analysis Toolkit (and Library)
4
4
 
5
5
  A comprehensive static analysis tool for Python source code that provides symbol table generation, call graph analysis, and semantic analysis using Jedi, CodeQL, and Tree-sitter.
6
6
 
7
7
  ## Installation
8
8
 
9
- This project uses [uv](https://docs.astral.sh/uv/) for dependency management.
9
+ ```bash
10
+ pip install codeanalyzer-python
11
+ ```
10
12
 
11
13
  ### Prerequisites
12
14
 
13
- - [uv](https://docs.astral.sh/uv/getting-started/installation/) installed
14
- - Python 3.12 or higher. You can use `uv` to install Python if it's not already installed:
15
- ```bash
16
- uv python install 3.12
17
- ```
15
+ - Python 3.12 or higher
18
16
 
19
17
  #### System Package Requirements
20
18
 
@@ -56,20 +54,6 @@ pyenv global 3.12.0 # or pyenv local 3.12.0 for project-specific
56
54
 
57
55
  > **Note:** These packages are required as the tool uses Python's built-in `venv` module to create isolated environments for analysis.
58
56
 
59
- ### Setup
60
-
61
- 1. Clone the repository:
62
- ```bash
63
- git clone https://github.com/codellm-devkit/codeanalyzer-python
64
- cd codeanalyzer-python
65
- ```
66
-
67
- 2. Install dependencies using uv:
68
- ```bash
69
- uv sync --all-groups
70
- ```
71
- This will install all dependencies including development and test dependencies.
72
-
73
57
  ## Usage
74
58
 
75
59
  The codeanalyzer provides a command-line interface for performing static analysis on Python projects.
@@ -77,15 +61,15 @@ The codeanalyzer provides a command-line interface for performing static analysi
77
61
  ### Basic Usage
78
62
 
79
63
  ```bash
80
- uv run codeanalyzer --input /path/to/python/project
64
+ codeanalyzer --input /path/to/python/project
81
65
  ```
82
66
 
83
67
  ### Command Line Options
84
68
 
85
- To view the available options and commands, run `uv run codeanalyzer --help`. You should see output similar to the following:
69
+ To view the available options and commands, run `codeanalyzer --help`. You should see output similar to the following:
86
70
 
87
71
  ```bash
88
- uv run codeanalyzer --help
72
+ ❯ codeanalyzer --help
89
73
 
90
74
  Usage: codeanalyzer [OPTIONS] COMMAND [ARGS]...
91
75
 
@@ -109,38 +93,38 @@ To view the available options and commands, run `uv run codeanalyzer --help`. Yo
109
93
 
110
94
  1. **Basic analysis with symbol table:**
111
95
  ```bash
112
- uv run codeanalyzer --input ./my-python-project
96
+ codeanalyzer --input ./my-python-project
113
97
  ```
114
98
 
115
99
  This will print the symbol table to stdout in JSON format to the standard output. If you want to save the output, you can use the `--output` option.
116
100
 
117
101
  ```bash
118
- uv run codeanalyzer --input ./my-python-project --output /path/to/analysis-results
102
+ codeanalyzer --input ./my-python-project --output /path/to/analysis-results
119
103
  ```
120
104
 
121
105
  Now, you can find the analysis results in `analysis.json` in the specified directory.
122
106
 
123
107
  2. **Toggle analysis levels with `--analysis-level`:**
124
108
  ```bash
125
- uv run codeanalyzer --input ./my-python-project --analysis-level 1 # Symbol table only
109
+ codeanalyzer --input ./my-python-project --analysis-level 1 # Symbol table only
126
110
  ```
127
111
  Call graph analysis can be enabled by setting the level to `2`:
128
112
  ```bash
129
- uv run codeanalyzer --input ./my-python-project --analysis-level 2 # Symbol table + Call graph
113
+ codeanalyzer --input ./my-python-project --analysis-level 2 # Symbol table + Call graph
130
114
  ```
131
115
  ***Note: The `--analysis-level=2` is not yet implemented in this version.***
132
116
 
133
117
  3. **Analysis with CodeQL enabled:**
134
118
  ```bash
135
- uv run codeanalyzer --input ./my-python-project --codeql
119
+ codeanalyzer --input ./my-python-project --codeql
136
120
  ```
137
- This will perform CodeQL-based analysis in addition to the standard symbol table generation.
138
-
121
+ This will perform CodeQL-based analysis in addition to the standard symbol table generation.
122
+
139
123
  ***Note: Not yet fully implemented. Please refrain from using this option until further notice.***
140
124
 
141
125
  4. **Eager analysis with custom cache directory:**
142
126
  ```bash
143
- uv run codeanalyzer --input ./my-python-project --eager --cache-dir /path/to/custom-cache
127
+ codeanalyzer --input ./my-python-project --eager --cache-dir /path/to/custom-cache
144
128
  ```
145
129
  This will rebuild the analysis cache at every run and store it in `/path/to/custom-cache/.codeanalyzer`. The cache will be cleared by default after analysis unless you specify `--keep-cache`.
146
130
 
@@ -148,7 +132,7 @@ To view the available options and commands, run `uv run codeanalyzer --help`. Yo
148
132
 
149
133
  5. **Quiet mode (minimal output):**
150
134
  ```bash
151
- uv run codeanalyzer --input /path/to/my-python-project --quiet
135
+ codeanalyzer --input /path/to/my-python-project --quiet
152
136
  ```
153
137
 
154
138
  ### Output
@@ -157,10 +141,36 @@ By default, analysis results are printed to stdout in JSON format. When using th
157
141
 
158
142
  ## Development
159
143
 
144
+ This project uses [uv](https://docs.astral.sh/uv/) for dependency management during development.
145
+
146
+ ### Development Setup
147
+
148
+ 1. Install [uv](https://docs.astral.sh/uv/getting-started/installation/)
149
+
150
+ 2. Clone the repository:
151
+ ```bash
152
+ git clone https://github.com/codellm-devkit/codeanalyzer-python
153
+ cd codeanalyzer-python
154
+ ```
155
+
156
+ 3. Install dependencies using uv:
157
+ ```bash
158
+ uv sync --all-groups
159
+ ```
160
+ This will install all dependencies including development and test dependencies.
161
+
162
+ ### Running from Source
163
+
164
+ When developing, you can run the tool directly from source:
165
+
166
+ ```bash
167
+ uv run codeanalyzer --input /path/to/python/project
168
+ ```
169
+
160
170
  ### Running Tests
161
171
 
162
172
  ```bash
163
- uv run pytest --pspec -s
173
+ uv run pytest --pspec -s
164
174
  ```
165
175
 
166
176
  ### Development Dependencies
@@ -1,11 +1,16 @@
1
- from contextlib import nullcontext
2
- import sys
3
- import typer
4
- from typing import Optional, Annotated
5
1
  from pathlib import Path
6
- from codeanalyzer.utils import _set_log_level
7
- from codeanalyzer.utils import logger
2
+ from typing import Annotated, Optional
3
+ from enum import Enum
4
+
5
+ import typer
6
+
8
7
  from codeanalyzer.core import AnalyzerCore
8
+ from codeanalyzer.utils import _set_log_level, logger
9
+
10
+
11
+ class OutputFormat(str, Enum):
12
+ JSON = "json"
13
+ MSGPACK = "msgpack"
9
14
 
10
15
 
11
16
  def main(
@@ -16,6 +21,15 @@ def main(
16
21
  Optional[Path],
17
22
  typer.Option("-o", "--output", help="Output directory for artifacts."),
18
23
  ] = None,
24
+ format: Annotated[
25
+ OutputFormat,
26
+ typer.Option(
27
+ "-f",
28
+ "--format",
29
+ help="Output format: json or msgpack.",
30
+ case_sensitive=False,
31
+ ),
32
+ ] = OutputFormat.JSON,
19
33
  analysis_level: Annotated[
20
34
  int,
21
35
  typer.Option("-a", "--analysis-level", help="1: symbol table, 2: call graph."),
@@ -57,16 +71,40 @@ def main(
57
71
  input, analysis_level, using_codeql, rebuild_analysis, cache_dir, clear_cache
58
72
  ) as analyzer:
59
73
  artifacts = analyzer.analyze()
60
- print_stream = sys.stdout
61
- stream_context = nullcontext(print_stream)
62
74
 
63
- if output is not None:
75
+ # Handle output based on format
76
+ if output is None:
77
+ # Output to stdout (only for JSON)
78
+ if format == OutputFormat.JSON:
79
+ print(artifacts.model_dump_json(separators=(",", ":")))
80
+ else:
81
+ logger.error(
82
+ f"Format '{format.value}' requires an output directory (use -o/--output)"
83
+ )
84
+ raise typer.Exit(code=1)
85
+ else:
86
+ # Output to file
64
87
  output.mkdir(parents=True, exist_ok=True)
65
- output_file = output / "analysis.json"
66
- stream_context = output_file.open("w")
88
+ _write_output(artifacts, output, format)
89
+
90
+
91
+ def _write_output(artifacts, output_dir: Path, format: OutputFormat):
92
+ """Write artifacts to file in the specified format."""
93
+ if format == OutputFormat.JSON:
94
+ output_file = output_dir / "analysis.json"
95
+ with output_file.open("w") as f:
96
+ f.write(artifacts.model_dump_json(separators=(",", ":")))
97
+ logger.info(f"Analysis saved to {output_file}")
67
98
 
68
- with stream_context as f:
69
- print(artifacts.model_dump_json(indent=4), file=f)
99
+ elif format == OutputFormat.MSGPACK:
100
+ output_file = output_dir / "analysis.msgpack"
101
+ msgpack_data = artifacts.to_msgpack_bytes()
102
+ with output_file.open("wb") as f:
103
+ f.write(msgpack_data)
104
+ logger.info(f"Analysis saved to {output_file}")
105
+ logger.info(
106
+ f"Compression ratio: {artifacts.get_compression_ratio():.1%} of JSON size"
107
+ )
70
108
 
71
109
 
72
110
  app = typer.Typer(
@@ -1,19 +1,16 @@
1
1
  import hashlib
2
2
  import os
3
- from pdb import set_trace
4
3
  import shutil
5
4
  import subprocess
6
- from pathlib import Path
7
5
  import sys
8
- from typing import Any, Dict, Union, Optional
9
- from codeanalyzer.utils import logger
6
+ from pathlib import Path
7
+ from typing import Any, Dict, Optional, Union
10
8
 
11
9
  from codeanalyzer.schema.py_schema import PyApplication, PyModule
12
10
  from codeanalyzer.semantic_analysis.codeql import CodeQLLoader
13
- from codeanalyzer.semantic_analysis.codeql.codeql_exceptions import (
14
- CodeQLExceptions,
15
- )
11
+ from codeanalyzer.semantic_analysis.codeql.codeql_exceptions import CodeQLExceptions
16
12
  from codeanalyzer.syntactic_analysis.symbol_table_builder import SymbolTableBuilder
13
+ from codeanalyzer.utils import logger
17
14
 
18
15
 
19
16
  class AnalyzerCore:
@@ -290,11 +287,7 @@ class AnalyzerCore:
290
287
 
291
288
  def analyze(self) -> PyApplication:
292
289
  """Return the path to the CodeQL database."""
293
- return (
294
- PyApplication.builder()
295
- .with_symbol_table(self._build_symbol_table())
296
- .build()
297
- )
290
+ return PyApplication.builder().symbol_table(self._build_symbol_table()).build()
298
291
 
299
292
  def _compute_checksum(self, root: Path) -> str:
300
293
  """Compute SHA256 checksum of all Python source files in a project directory. If somethings changes, the
@@ -1,13 +1,13 @@
1
1
  from .py_schema import (
2
2
  PyApplication,
3
- PyImport,
3
+ PyCallable,
4
+ PyCallableParameter,
5
+ PyClass,
6
+ PyClassAttribute,
4
7
  PyComment,
8
+ PyImport,
5
9
  PyModule,
6
- PyClass,
7
10
  PyVariableDeclaration,
8
- PyCallable,
9
- PyClassAttribute,
10
- PyCallableParameter
11
11
  )
12
12
 
13
13
  __all__ = [
@@ -19,5 +19,5 @@ __all__ = [
19
19
  "PyVariableDeclaration",
20
20
  "PyCallable",
21
21
  "PyClassAttribute",
22
- "PyCallableParameter"
22
+ "PyCallableParameter",
23
23
  ]