Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
157 commits
Select commit Hold shift + click to select a range
e953c74
Added python plugin based on dummy and cpp
Oct 12, 2023
d2a788a
PythonService basic implementations
Oct 12, 2023
aea9a3e
Added PythonService file types
Oct 13, 2023
9458716
Python plugin webgui
Oct 16, 2023
0befbc4
Python plugin webgui infotree
Oct 16, 2023
794ada9
Added Python InfoTree and Menu
Oct 19, 2023
b3fc4af
pythonplugin basic parser
Nov 27, 2023
876adcd
python parser
Nov 30, 2023
c782313
pythonplugin model
Dec 4, 2023
ddae076
PYName model
Feb 13, 2024
83a35e9
PythonParser parse function
Feb 13, 2024
85a233e
PythonParser parsing a file
Feb 14, 2024
0799214
PYName hash
Feb 14, 2024
5898fa5
Inserting PYName into database
Feb 16, 2024
2f5cbe8
PYName added file_id
Feb 16, 2024
f323c84
PythonService queries PYName from database
Feb 16, 2024
e6e280c
Update PyName hash function
Feb 19, 2024
a1e2a0a
PythonService find references.
Feb 20, 2024
7b9182f
Added support for Python virtual environments.
Feb 21, 2024
b7d6f38
Log parse results.
Feb 22, 2024
e98bebf
PythonParser prepare input
Feb 22, 2024
278e7cf
PythonParser adding more parse statistics.
Feb 23, 2024
5ce24c9
PythonParser removed venv_config
Feb 23, 2024
bd66c9f
PythonParser handle missing modules, added type hint
Feb 23, 2024
1d7fc4f
PythonService display properties.
Feb 23, 2024
7696a84
PythonParser Adding imported files to database.
Feb 23, 2024
08e00c1
PythonParser module definition should be the module itself.
Feb 23, 2024
93c8ef6
PythonParser Flags for additional syspath.
Feb 26, 2024
41c6a5a
PythonService Fix astNodeID
Feb 27, 2024
977d609
PythonParser multiprocess
Mar 4, 2024
0cedba6
PythonParser multiprocess flag
Mar 5, 2024
ce24d48
PythonParser logging
Mar 5, 2024
4a6d6a9
PythonParser Fix missing module report
Mar 5, 2024
165774c
Include missing headers
Mar 14, 2024
0eefff2
PythonParser simplify parsing finished message
Mar 18, 2024
d21354b
Python syntax highlight
Mar 20, 2024
1849917
PythonService skip imports from definition
Mar 20, 2024
c6a0114
PythonService order results by line_start
Mar 25, 2024
2d03c14
PythonService Set range for selected node
Mar 25, 2024
cff8fc4
PythonParser Parent PYName
Mar 26, 2024
ddc5639
PythonService Class methods and data members
Mar 26, 2024
3d59309
PythonService Added utility functions
Mar 27, 2024
c9dd751
PythonService Added support for class references, function local vari…
Mar 27, 2024
34de013
PythonService Added reference list type hints, parent node
Apr 22, 2024
d45c6d9
PythonService Added parameter references
Apr 22, 2024
9cce963
PythonService Added getAstNodeInfo
Jul 11, 2024
ad1af9a
PyParser filter Python files before multiprocessing
Jul 25, 2024
7809c17
PyParser simplify name position info
Aug 20, 2024
4e37378
PyParser refactor
Aug 20, 2024
cf61bc0
PyParser PosInfo, ASTHelper
Aug 20, 2024
8676dcd
PyParser isFunctionCall handle attribute case
Aug 31, 2024
f0fd128
PythonService this calls
Aug 31, 2024
d0eb374
Webgui Function call icon
Sep 1, 2024
6e30edd
PythonService Usage - ignore same PYName
Sep 1, 2024
c14213e
PythonPlugin venv
Sep 3, 2024
8260143
ignore .cache
Sep 3, 2024
c5c5ca2
PyParser Catch jedi errors
Sep 4, 2024
7f4f51b
PythonService less transaction
Sep 5, 2024
3a78ef0
PyParser Highlight venv path error
Sep 5, 2024
585bc3d
PyParser safe environment config
Sep 5, 2024
3c20947
PyParser Better logging of messages
Sep 5, 2024
ad655f7
[Diagrams] Function call diagram WIP
Sep 10, 2024
b09f663
[PythonService] Function call diagram
Sep 14, 2024
170fcd8
[Diagrams] Find parent function
Sep 15, 2024
f85057f
[PythonService] getSourceText
Sep 15, 2024
bce8463
[PyParser] Add all definition import paths
Sep 16, 2024
afafa60
[Diagrams] Make certain nodes unclickable
Sep 17, 2024
bea0462
[Diagrams] Function call diagram file paths
Sep 17, 2024
a1c3146
[Diagrams] Fix node decoration types
Sep 17, 2024
c24af0c
[PyParser] Use asthelper for is_import
Sep 17, 2024
600d1d9
[Diagrams] Fix node decoration types again
Sep 17, 2024
ad522a1
[Model] Database indexes
Sep 17, 2024
92de548
[PythonService] queryNodes, module diagram
Sep 18, 2024
c4ceb39
[Diagrams] Refactor, module diagram
Sep 18, 2024
e2a426f
[PyParser] Set a value for entire module nodes
Sep 18, 2024
7ec3cb5
[Diagrams] Catch invalid file id exception
Sep 18, 2024
c770d0c
[Diagrams] Remove module nodes
Sep 19, 2024
8a0c53a
[Webgui] Handle AstNodes in a file diagram
Sep 20, 2024
e6ffa11
[PythonService] transformReferences, query definitions in file
Sep 20, 2024
3332a66
[Diagrams] Added imported usage to the module diagram
Sep 20, 2024
4f750bb
[Diagrams] Remove duplicate line nodes from module diagram
Sep 20, 2024
df7c668
[Diagrams] Usage diagrams
Sep 21, 2024
73bf692
[PythonService] Node not found exceptions
Sep 21, 2024
e615ec5
[PythonParser] Improve database insert
Sep 21, 2024
c174903
[PyParser] Make type_hint a config option
Sep 21, 2024
b9b0a05
[PyParser] Make ASTHelper faster
Sep 21, 2024
f5bd8d2
[PyParser] Only process definitions once
Sep 26, 2024
eaf3c4a
[PythonService] Debug build: ID, REF_ID, DEFINITION property
Sep 30, 2024
0ba4892
[PyParser] Only calculate PosInfo once
Oct 1, 2024
7b7f089
[PyParser] PYReference, getFileRefs
Oct 1, 2024
a529aa0
[PythonService] queryNodeByPosition: prefer shorter node values
Oct 1, 2024
cac9836
[PyParser] PYBuiltin
Oct 1, 2024
e0d3ca7
[Diagrams] Simplify module dependency diagram
Oct 1, 2024
a80d456
[PythonService] Refactor getDiagramTypes
Oct 1, 2024
75d515c
[PyParser] PosInfo dataclass
Oct 2, 2024
a5d35d3
[PyParser] ParserConfig
Oct 2, 2024
176bef5
[PyParser] PYReference error handling, stack trace config option
Oct 2, 2024
a3a0178
[PyParser] module_path should be str
Oct 2, 2024
94017a6
[PyParser] Stack trace warning color
Oct 2, 2024
dd5402c
[PyParser] PYBuiltin stack trace
Oct 5, 2024
e221850
[Diagrams] Use different color for builtin paths
Oct 5, 2024
5ffcc86
[PythonService] queryNodes ORDER BY is_builtin
Oct 5, 2024
13b1f44
[PyParser] PYBuiltin rework
Oct 5, 2024
3563459
[Diagrams] Fix file path color
Oct 5, 2024
7af1364
[PyParser] PYBuiltin stdlib submodules
Oct 5, 2024
95571d9
[Diagrams] Add a comment explanation to file path nodes
Oct 5, 2024
339f5de
[Diagrams] Diagram Legend
Oct 5, 2024
99bb3f9
[Diagrams] Remove border from certain file path nodes
Oct 6, 2024
e7bf85b
[Diagrams] Class diagram
Oct 6, 2024
fe5aef4
[PyParser] astparam
Oct 6, 2024
5a77cb7
[PyParser] PYName path, move getHashName to parserutil
Oct 9, 2024
077c2c7
[PyParser] NodeInfo, ASThelper path
Oct 9, 2024
5d41697
[PyParser] Annotations
Oct 12, 2024
7683687
Graphviz Cairo SVG rendering
Oct 12, 2024
4d0ab32
[Diagrams] Class diagram return annotation, syntax highlight
Oct 12, 2024
f670fc6
[PyParser] getSubclass
Oct 13, 2024
694116d
[PythonService] Base class
Oct 13, 2024
b43c9bf
[Diagrams] Class diagram base class
Oct 13, 2024
cf41b79
[PyParser] Rewrite definition handling
Oct 15, 2024
3a3024e
[PyParser] More config options
Oct 15, 2024
c144637
[PyParser] AST function signature
Oct 15, 2024
1bcfc69
[PyParser] Added more config options
Oct 15, 2024
7fce5d3
[PyParser] log_config
Oct 15, 2024
bf2f6aa
[PyParser] ParseResult
Oct 15, 2024
e96899c
[PyParser] __getPosValue, getFunctionParam
Oct 16, 2024
2a22a8b
[Diagrams] Class diagram variable highlight fix
Oct 16, 2024
325a7e9
[PyParser] Expand __getASTValue
Oct 16, 2024
1484a42
[PythonParser] CLI arguments
Oct 21, 2024
4e09adf
[PyParser] Submodule discovery
Nov 16, 2024
b2e0588
[PythonTest] Parser test
Nov 17, 2024
0e64582
[PythonTest] Service test
Nov 17, 2024
d751e68
[Webgui] Fix caller infinite grouping
Nov 18, 2024
6d71714
[Webgui] Cleanup
Nov 18, 2024
b5b5a74
[PythonParser] Remove accept function
Nov 18, 2024
2fc6aa3
[PyParser] Refactor getFunctionSignature
Nov 18, 2024
9dccf4b
[PyParser] Fix annotation overwritten by jedi node
Nov 20, 2024
aeea6c9
[PythonTest] Parser test - functions
Nov 20, 2024
1387b09
[PythonTest] Parser test - class inheritance
Nov 20, 2024
e4ac5af
[PythonTest] Parser test - queryFile
Nov 20, 2024
c258015
[PythonTest] Parser test - class methods, local variables
Nov 20, 2024
174941a
[PythonTest] Parser test - imports
Nov 20, 2024
115451f
[PythonTest] Parser test - builtin variable
Nov 20, 2024
9354070
[PythonTest] Parser test - ClassType, ReferenceID
Nov 23, 2024
ef17067
[PythonTest] Service test - node properties, reference tests
Nov 23, 2024
8e4a5d5
pycache gitignore
Nov 23, 2024
e1d1e73
[PythonService] move boolToString to util
Nov 23, 2024
c3e4ec7
[PythonService] Cleanup
Nov 23, 2024
05941f3
[PythonService] Make PythonDiagram friend class
Nov 23, 2024
a3c64cb
[PythonService] Debug message spacing
Nov 23, 2024
f538fa4
[PythonParser] parse() string ref
Nov 24, 2024
4940e05
[PyParser] ASTHelper __equalPos
Nov 24, 2024
7b08b09
[Diagrams] Use relative path
Nov 24, 2024
cbc3cfe
[PythonService] Remove getProperties message for release builds
Dec 1, 2024
3862dcd
Fix compilation warnings.
Feb 25, 2025
c799d5b
Added file refs option.
Feb 27, 2025
2b1168a
Added Python plugin documentation.
Feb 27, 2025
4ddb215
Do not share list objects across dataclasses
barnabasdomozi Sep 23, 2025
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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ nbproject/
# Vim
*.swp

# clangd cache
.cache/

## Build folders
build/
Expand Down
3 changes: 3 additions & 0 deletions Config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ set(INSTALL_GEN_DIR "${INSTALL_SCRIPTS_DIR}/generated")
# Installation directory for Java libraries
set(INSTALL_JAVA_LIB_DIR "${INSTALL_LIB_DIR}/java")

# Installation directory for the Python plugin
set(INSTALL_PYTHON_DIR "${INSTALL_LIB_DIR}/pythonplugin")

# Installation directory for executables
set(INSTALL_BIN_DIR "bin")

Expand Down
123 changes: 123 additions & 0 deletions doc/pythonplugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Python Plugin

## Parsing Python projects
Python projects can be parsed by using the `CodeCompass_parser` executable.
See its usage [in a seperate document](/doc/usage.md).

## Python specific parser flags

### Python dependencies
Large Python projects usually have multiple Python package dependencies.
Although a given project can be parsed without installing any of its dependencies, it is strongly recommended
that the required modules are installed in order to achieve a complete parsing.
To install a project's dependencies, create a [Python virtual environment](https://docs.python.org/3/library/venv.html)
and install the necessary packages.
When parsing a project, specify the virtual environment path so the parser can successfully resolve the dependencies:
```
--venvpath <path to virtual environment>
```

### Type hints
The parser can try to determine Python type hints for variables, expressions and functions.
It can work out type hints such as `Iterable[int]` or `Union[int, str]`.
However, this process can be extremely slow, especially for functions, thus it is disabled by default.
It can be enabled using the `--type-hint` flag.

### Python submodules
Large Python projects can have internal submodules and the parser tries to locate them automatically.
Specifically, it looks for `__init__.py` files and considers those folders modules.
This process is called submodule discovery and can be disabled using the `--disable-submodule-discovery` flag.

You can also add submodules manually by adding those specific paths to the parser's syspath:
```
--syspath <path>
```
For more information, see the [Python syspath docs](https://docs.python.org/3/library/sys.html#sys.path).

### File references
By default, the parser works out references by looking for definitions only - if nodes share the same definition
they are considered references.
However, this method sometimes misses a few references (e.g. local variables in a function).
To extend search for references in a file context, apply the `--file-refs` flag.
Note that using this option can potentially extend the total parsing time.

## Examples of parsing Python projects

### Flask
We downloaded [flask 3.1.0](https://github.com/pallets/flask/releases/tag/3.1.0) source code to `~/parsing/flask/`.
The first step is to create a Python virtual environment and install flask's dependencies.
Create a Python virtual environment and activate it:
```bash
cd ~/parsing/flask/
python3 -m venv venv
source venv/bin/activate
```
Next, we install the required dependencies listed in `pyproject.toml`.
```bash
pip install .
```
Further dependencies include development packages listed in `requirements/dev.txt`.
These can be also installed using `pip`.
```bash
pip install -r requirements/dev.txt
```
Finally, we can run `CodeCompass_parser`.
```bash
CodeCompass_parser \
-n flask \
-i ~/parsing/flask/ \
-w ~/parsing/workdir/ \
-d "pgsql:host=localhost;port=5432;user=compass;password=pass;database=flask" \
-f \
--venvpath ~/parsing/flask/venv/ \
--label src=~/parsing/flask/
```

### CodeChecker
We downloaded [CodeChecker 6.24.4](https://github.com/Ericsson/codechecker/releases/tag/v6.24.4) source code to `~/parsing/codechecker`.
CodeChecker has an automated way of creating a Python virtual environment and installing dependencies - by running the `venv` target of a Makefile:
```bash
cd ~/parsing/codechecker/
make venv
```
Next, we can run `CodeCompass_parser`.
```bash
CodeCompass_parser \
-n codechecker \
-i ~/parsing/codechecker/ \
-w ~/parsing/workdir/ \
-d "pgsql:host=localhost;port=5432;user=compass;password=pass;database=codechecker" \
-f \
--venvpath ~/parsing/codechecker/venv/ \
--label src=~/parsing/codechecker/
```

## Troubleshooting
A few errors can occur during the parsing process, these are highlighted in color red.
The stack trace is hidden by default, and can be shown using the `--stack-trace` flag.

### Failed to use virtual environment
This error can appear if one specifies the `--venvpath` option during parsing.
The parser tried to use the specified virtual environment path, however it failed.

#### Solution
Double check that the Python virtual environment is correctly setup and its
path is correct.
If the error still persists, apply the `--stack-trace` parser option
to view a more detailed stack trace of the error.

### Missing module (file = path line = number)
In this case, the parser tried to parse a given Python file, however it
could not find a definition for a module.
Commonly, the Python file imports another module and the parser cannot locate this module.
If this happens, the Python file is marked *partial* indicating that
a module definition was not resolved in this file.
The error message displays the module name, exact file path and line number
so one can further troubleshoot this problem.

#### Solution
Ensure that the `--venvpath` option is correctly specified and all the required
dependencies are installed in that Python virtual environment.
If the imported module is part of the parsed project, use the `--syspath` option
and specify the directory where the module is located in.

6 changes: 6 additions & 0 deletions plugins/python/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_subdirectory(model)
add_subdirectory(parser)
add_subdirectory(service)
add_subdirectory(test)

install_webplugin(webgui)
10 changes: 10 additions & 0 deletions plugins/python/model/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
set(ODB_SOURCES
include/model/pyname.h
)

generate_odb_files("${ODB_SOURCES}")

add_odb_library(pythonmodel ${ODB_CXX_SOURCES})
target_link_libraries(pythonmodel model)

install_sql()
53 changes: 53 additions & 0 deletions plugins/python/model/include/model/pyname.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef CC_MODEL_PYNAME_H
#define CC_MODEL_PYNAME_H

#include <cstdint>
#include <string>
#include <odb/core.hxx>

namespace cc
{
namespace model
{

enum PYNameID {
ID,
REF_ID,
PARENT,
PARENT_FUNCTION
};

#pragma db object
struct PYName
{
#pragma db id unique
std::uint64_t id = 0;

#pragma db index
std::uint64_t ref_id;

std::uint64_t parent;
std::uint64_t parent_function;

bool is_definition = false;
bool is_builtin = false;
bool is_import = false;
bool is_call = false;
std::string full_name;
std::string value;
std::string type;
std::string type_hint;

std::uint64_t line_start;
std::uint64_t line_end;
std::uint64_t column_start;
std::uint64_t column_end;

#pragma db index
std::uint64_t file_id;
};

}
}

#endif
1 change: 1 addition & 0 deletions plugins/python/parser/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
venv/
46 changes: 46 additions & 0 deletions plugins/python/parser/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
find_package(Boost REQUIRED COMPONENTS python)

include_directories(
include
${PROJECT_SOURCE_DIR}/model/include
${PROJECT_SOURCE_DIR}/util/include
${PROJECT_SOURCE_DIR}/parser/include
${PLUGIN_DIR}/model/include)

include_directories(SYSTEM
${Boost_INCLUDE_DIRS}
${Python3_INCLUDE_DIRS})

add_library(pythonparser SHARED
src/pythonparser.cpp)

target_link_libraries(pythonparser
model
pythonmodel
${Boost_LIBRARIES}
${Python3_LIBRARIES})

target_compile_options(pythonparser PUBLIC -Wno-unknown-pragmas)

set(VENV_DIR "${PLUGIN_DIR}/parser/venv/")
if(NOT EXISTS ${VENV_DIR})
message("Creating Python virtual environment: ${VENV_DIR}")
execute_process(
COMMAND python3 -m venv venv
WORKING_DIRECTORY ${PLUGIN_DIR}/parser/)
endif()

message("Installing Python dependencies...")
execute_process(
COMMAND venv/bin/pip install -r requirements.txt
WORKING_DIRECTORY ${PLUGIN_DIR}/parser/)

install(TARGETS pythonparser DESTINATION ${INSTALL_PARSER_DIR})
install(
DIRECTORY pyparser/
DESTINATION ${INSTALL_PYTHON_DIR}/pyparser)
install(
DIRECTORY venv/
DESTINATION ${INSTALL_PYTHON_DIR}/venv)

43 changes: 43 additions & 0 deletions plugins/python/parser/include/pythonparser/pythonparser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef CC_PARSER_PYTHONPARSER_H
#define CC_PARSER_PYTHONPARSER_H

#include <string>
#include <vector>
#include <map>
#include <parser/abstractparser.h>
#include <parser/parsercontext.h>
#include <parser/sourcemanager.h>
#include <util/parserutil.h>
#include <boost/python.hpp>
#include <model/pyname.h>
#include <model/pyname-odb.hxx>
namespace cc
{
namespace parser
{

namespace python = boost::python;

typedef std::unordered_map<std::uint64_t, model::PYName> PYNameMap;

class PythonParser : public AbstractParser
{
public:
PythonParser(ParserContext& ctx_);
virtual ~PythonParser();
virtual bool parse() override;
private:
struct ParseResultStats {
std::uint32_t partial;
std::uint32_t full;
};

python::object m_py_module;
void processFile(const python::object& obj, PYNameMap& map, ParseResultStats& parse_result);
void parseProject(const std::string& root_path);
};

} // parser
} // cc

#endif // CC_PARSER_PYTHONPARSER_H
Loading
Loading