memgraph-toolbox 0.1.0__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.
- memgraph_toolbox-0.1.0/.gitignore +174 -0
- memgraph_toolbox-0.1.0/.python-version +1 -0
- memgraph_toolbox-0.1.0/LICENSE +21 -0
- memgraph_toolbox-0.1.0/PKG-INFO +80 -0
- memgraph_toolbox-0.1.0/README.md +60 -0
- memgraph_toolbox-0.1.0/pyproject.toml +36 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/__init__.py +0 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/api/__init__.py +0 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/api/memgraph.py +98 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/api/tool.py +51 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/api/toolkit.py +41 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/py.typed +0 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tests/__init__.py +0 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tests/test_toolkit.py +35 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tests/test_tools.py +193 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tools/__init__.py +0 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tools/betweenness_centrality.py +57 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tools/config.py +23 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tools/constraint.py +23 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tools/cypher.py +33 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tools/index.py +23 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tools/page_rank.py +43 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tools/schema.py +22 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tools/storage.py +23 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/tools/trigger.py +23 -0
- memgraph_toolbox-0.1.0/src/memgraph_toolbox/utils/logging.py +15 -0
- memgraph_toolbox-0.1.0/uv.lock +84 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
#uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
#poetry.lock
|
|
109
|
+
|
|
110
|
+
# pdm
|
|
111
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
112
|
+
#pdm.lock
|
|
113
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
114
|
+
# in version control.
|
|
115
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
116
|
+
.pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
121
|
+
__pypackages__/
|
|
122
|
+
|
|
123
|
+
# Celery stuff
|
|
124
|
+
celerybeat-schedule
|
|
125
|
+
celerybeat.pid
|
|
126
|
+
|
|
127
|
+
# SageMath parsed files
|
|
128
|
+
*.sage.py
|
|
129
|
+
|
|
130
|
+
# Environments
|
|
131
|
+
.env
|
|
132
|
+
.venv
|
|
133
|
+
env/
|
|
134
|
+
venv/
|
|
135
|
+
ENV/
|
|
136
|
+
env.bak/
|
|
137
|
+
venv.bak/
|
|
138
|
+
|
|
139
|
+
# Spyder project settings
|
|
140
|
+
.spyderproject
|
|
141
|
+
.spyproject
|
|
142
|
+
|
|
143
|
+
# Rope project settings
|
|
144
|
+
.ropeproject
|
|
145
|
+
|
|
146
|
+
# mkdocs documentation
|
|
147
|
+
/site
|
|
148
|
+
|
|
149
|
+
# mypy
|
|
150
|
+
.mypy_cache/
|
|
151
|
+
.dmypy.json
|
|
152
|
+
dmypy.json
|
|
153
|
+
|
|
154
|
+
# Pyre type checker
|
|
155
|
+
.pyre/
|
|
156
|
+
|
|
157
|
+
# pytype static type analyzer
|
|
158
|
+
.pytype/
|
|
159
|
+
|
|
160
|
+
# Cython debug symbols
|
|
161
|
+
cython_debug/
|
|
162
|
+
|
|
163
|
+
# PyCharm
|
|
164
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
165
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
166
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
167
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
168
|
+
#.idea/
|
|
169
|
+
|
|
170
|
+
# Ruff stuff:
|
|
171
|
+
.ruff_cache/
|
|
172
|
+
|
|
173
|
+
# PyPI configuration file
|
|
174
|
+
.pypirc
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.10
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Memgraph
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: memgraph-toolbox
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Memgraph toolbox library for Memgraph AI tools and utilities
|
|
5
|
+
Author-email: antejavor <ante.javor@memgraph.io>
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: ai,graph,memgraph,toolkit
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Provides-Extra: test
|
|
17
|
+
Requires-Dist: pytest-asyncio>=0.26.0; extra == 'test'
|
|
18
|
+
Requires-Dist: pytest>=8.3.5; extra == 'test'
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# Memgraph Toolbox
|
|
22
|
+
|
|
23
|
+
The **Memgraph Toolbox** is a collection of tools designed to interact with a
|
|
24
|
+
Memgraph database. These tools provide functionality for querying, analyzing,
|
|
25
|
+
and managing data within Memgraph, making it easier to work with graph data.
|
|
26
|
+
They are made to be easily called from other framework implementations such as
|
|
27
|
+
**MCP**, **Langchain** or **Lamaindex**.
|
|
28
|
+
|
|
29
|
+
## Available Tools
|
|
30
|
+
|
|
31
|
+
Below is a list of tools included in the toolbox, along with their descriptions:
|
|
32
|
+
|
|
33
|
+
1. `ShowTriggersTool` - Shows trigger information from a Memgraph database.
|
|
34
|
+
2. `ShowStorageInfoTool` - Shows storage information from a Memgraph database.
|
|
35
|
+
3. `ShowSchemaInfoTool` - Shows schema information from a Memgraph database.
|
|
36
|
+
4. `PageRankTool` - Calculates PageRank on a graph in Memgraph.
|
|
37
|
+
5. `ShowIndexInfoTool` - Shows index information from a Memgraph database.
|
|
38
|
+
6. `CypherTool` - Executes arbitrary Cypher queries on a Memgraph database.
|
|
39
|
+
7. `ShowConstraintInfoTool` - Shows constraint information from a Memgraph database.
|
|
40
|
+
8. `ShowConfigTool` - Shows configuration information from a Memgraph database.
|
|
41
|
+
9. `BetweennessCentralityTool` - Calculates betweenness centrality for nodes in a graph.
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
Each tool is implemented as a Python class inheriting from `BaseTool`. To use a
|
|
46
|
+
tool:
|
|
47
|
+
|
|
48
|
+
1. Instantiate the tool with a `Memgraph` database connection.
|
|
49
|
+
2. Call the `call` method with the required arguments.
|
|
50
|
+
|
|
51
|
+
Example:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from memgraph_toolbox.tools.trigger import ShowTriggersTool
|
|
55
|
+
from memgraph_toolbox.api.memgraph import Memgraph
|
|
56
|
+
|
|
57
|
+
# Connect to Memgraph
|
|
58
|
+
db = Memgraph()
|
|
59
|
+
|
|
60
|
+
# Use the ShowTriggersTool
|
|
61
|
+
tool = ShowTriggersTool(db)
|
|
62
|
+
triggers = tool.call({})
|
|
63
|
+
print(triggers)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Requirements
|
|
67
|
+
|
|
68
|
+
- Python 3.10+
|
|
69
|
+
- Memgraph database
|
|
70
|
+
- Memgraph Mage (for certain tools like `pagerank` and `run_betweenness_centrality`)
|
|
71
|
+
|
|
72
|
+
## Contributing
|
|
73
|
+
|
|
74
|
+
Contributions are welcome! Feel free to submit issues or pull requests to
|
|
75
|
+
improve the toolbox.
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
This project is licensed under the MIT License. See the `LICENSE` file for
|
|
80
|
+
details.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Memgraph Toolbox
|
|
2
|
+
|
|
3
|
+
The **Memgraph Toolbox** is a collection of tools designed to interact with a
|
|
4
|
+
Memgraph database. These tools provide functionality for querying, analyzing,
|
|
5
|
+
and managing data within Memgraph, making it easier to work with graph data.
|
|
6
|
+
They are made to be easily called from other framework implementations such as
|
|
7
|
+
**MCP**, **Langchain** or **Lamaindex**.
|
|
8
|
+
|
|
9
|
+
## Available Tools
|
|
10
|
+
|
|
11
|
+
Below is a list of tools included in the toolbox, along with their descriptions:
|
|
12
|
+
|
|
13
|
+
1. `ShowTriggersTool` - Shows trigger information from a Memgraph database.
|
|
14
|
+
2. `ShowStorageInfoTool` - Shows storage information from a Memgraph database.
|
|
15
|
+
3. `ShowSchemaInfoTool` - Shows schema information from a Memgraph database.
|
|
16
|
+
4. `PageRankTool` - Calculates PageRank on a graph in Memgraph.
|
|
17
|
+
5. `ShowIndexInfoTool` - Shows index information from a Memgraph database.
|
|
18
|
+
6. `CypherTool` - Executes arbitrary Cypher queries on a Memgraph database.
|
|
19
|
+
7. `ShowConstraintInfoTool` - Shows constraint information from a Memgraph database.
|
|
20
|
+
8. `ShowConfigTool` - Shows configuration information from a Memgraph database.
|
|
21
|
+
9. `BetweennessCentralityTool` - Calculates betweenness centrality for nodes in a graph.
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
Each tool is implemented as a Python class inheriting from `BaseTool`. To use a
|
|
26
|
+
tool:
|
|
27
|
+
|
|
28
|
+
1. Instantiate the tool with a `Memgraph` database connection.
|
|
29
|
+
2. Call the `call` method with the required arguments.
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from memgraph_toolbox.tools.trigger import ShowTriggersTool
|
|
35
|
+
from memgraph_toolbox.api.memgraph import Memgraph
|
|
36
|
+
|
|
37
|
+
# Connect to Memgraph
|
|
38
|
+
db = Memgraph()
|
|
39
|
+
|
|
40
|
+
# Use the ShowTriggersTool
|
|
41
|
+
tool = ShowTriggersTool(db)
|
|
42
|
+
triggers = tool.call({})
|
|
43
|
+
print(triggers)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Requirements
|
|
47
|
+
|
|
48
|
+
- Python 3.10+
|
|
49
|
+
- Memgraph database
|
|
50
|
+
- Memgraph Mage (for certain tools like `pagerank` and `run_betweenness_centrality`)
|
|
51
|
+
|
|
52
|
+
## Contributing
|
|
53
|
+
|
|
54
|
+
Contributions are welcome! Feel free to submit issues or pull requests to
|
|
55
|
+
improve the toolbox.
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
|
|
59
|
+
This project is licensed under the MIT License. See the `LICENSE` file for
|
|
60
|
+
details.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "memgraph-toolbox"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Memgraph toolbox library for Memgraph AI tools and utilities"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "antejavor", email = "ante.javor@memgraph.io" }
|
|
8
|
+
]
|
|
9
|
+
license = { text = "MIT" }
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
url = "https://github.com/memgraph/ai-toolkit"
|
|
12
|
+
|
|
13
|
+
keywords = ["memgraph", "graph", "ai", "toolkit"]
|
|
14
|
+
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.optional-dependencies]
|
|
25
|
+
test = [
|
|
26
|
+
"pytest>=8.3.5",
|
|
27
|
+
"pytest-asyncio>=0.26.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[build-system]
|
|
31
|
+
requires = ["hatchling", "build"]
|
|
32
|
+
build-backend = "hatchling.build"
|
|
33
|
+
|
|
34
|
+
[tool.pytest.ini_options]
|
|
35
|
+
log_cli = true
|
|
36
|
+
log_cli_level = "INFO"
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Optional
|
|
2
|
+
|
|
3
|
+
from neo4j import GraphDatabase
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Memgraph:
|
|
7
|
+
"""
|
|
8
|
+
Base Memgraph client for interacting with Memgraph database.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
uri: str,
|
|
14
|
+
username: str,
|
|
15
|
+
password: str,
|
|
16
|
+
driver_config: Optional[Dict] = None,
|
|
17
|
+
):
|
|
18
|
+
self.driver = GraphDatabase.driver(
|
|
19
|
+
uri, auth=(username, password), **(driver_config or {})
|
|
20
|
+
)
|
|
21
|
+
try:
|
|
22
|
+
import neo4j
|
|
23
|
+
except ImportError:
|
|
24
|
+
raise ImportError(
|
|
25
|
+
"Could not import neo4j python package. "
|
|
26
|
+
"Please install it with `pip install neo4j`."
|
|
27
|
+
)
|
|
28
|
+
try:
|
|
29
|
+
self.driver.verify_connectivity()
|
|
30
|
+
except neo4j.exceptions.ServiceUnavailable:
|
|
31
|
+
raise ValueError(
|
|
32
|
+
"Could not connect to Memgraph database. "
|
|
33
|
+
"Please ensure that the url is correct"
|
|
34
|
+
)
|
|
35
|
+
except neo4j.exceptions.AuthError:
|
|
36
|
+
raise ValueError(
|
|
37
|
+
"Could not connect to Memgraph database. "
|
|
38
|
+
"Please ensure that the username and password are correct"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def query(self, query: str, params: dict = {}) -> List[Dict[str, Any]]:
|
|
42
|
+
"""
|
|
43
|
+
Execute a Cypher query and return results as a list of dictionaries.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
query: The Cypher query to execute
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
List of dictionaries containing query results
|
|
50
|
+
"""
|
|
51
|
+
from neo4j.exceptions import Neo4jError
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
data, _, _ = self.driver.execute_query(
|
|
55
|
+
query,
|
|
56
|
+
parameters_=params,
|
|
57
|
+
)
|
|
58
|
+
json_data = [r.data() for r in data]
|
|
59
|
+
return json_data
|
|
60
|
+
except Neo4jError as e:
|
|
61
|
+
if not (
|
|
62
|
+
(
|
|
63
|
+
( # isCallInTransactionError
|
|
64
|
+
e.code == "Neo.DatabaseError.Statement.ExecutionFailed"
|
|
65
|
+
or e.code
|
|
66
|
+
== "Neo.DatabaseError.Transaction.TransactionStartFailed"
|
|
67
|
+
)
|
|
68
|
+
and "in an implicit transaction" in e.message
|
|
69
|
+
)
|
|
70
|
+
or ( # isPeriodicCommitError
|
|
71
|
+
e.code == "Neo.ClientError.Statement.SemanticError"
|
|
72
|
+
and (
|
|
73
|
+
"in an open transaction is not possible" in e.message
|
|
74
|
+
or "tried to execute in an explicit transaction" in e.message
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
or (
|
|
78
|
+
e.code == "Memgraph.ClientError.MemgraphError.MemgraphError"
|
|
79
|
+
and ("in multicommand transactions" in e.message)
|
|
80
|
+
)
|
|
81
|
+
or (
|
|
82
|
+
e.code == "Memgraph.ClientError.MemgraphError.MemgraphError"
|
|
83
|
+
and "SchemaInfo disabled" in e.message
|
|
84
|
+
)
|
|
85
|
+
):
|
|
86
|
+
raise
|
|
87
|
+
|
|
88
|
+
# fallback to allow implicit transactions
|
|
89
|
+
with self.driver.session() as session:
|
|
90
|
+
data = session.run(query, params)
|
|
91
|
+
json_data = [r.data() for r in data]
|
|
92
|
+
return json_data
|
|
93
|
+
|
|
94
|
+
def close(self) -> None:
|
|
95
|
+
"""
|
|
96
|
+
Close the database connection.
|
|
97
|
+
"""
|
|
98
|
+
self.driver.close()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Dict, List
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BaseTool(ABC):
|
|
6
|
+
"""
|
|
7
|
+
Base class for all tools.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
name: str
|
|
11
|
+
description: str
|
|
12
|
+
input_schema: Dict[str, Any]
|
|
13
|
+
|
|
14
|
+
def __init__(self, name: str, description: str, input_schema: Dict[str, Any]):
|
|
15
|
+
self.name = name
|
|
16
|
+
self.description = description
|
|
17
|
+
self.input_schema = input_schema
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def call(self, arguments: Dict[str, Any]) -> List[Any]:
|
|
21
|
+
"""
|
|
22
|
+
Execute the tool with the provided arguments.
|
|
23
|
+
|
|
24
|
+
Parameters:
|
|
25
|
+
arguments (dict): A dictionary of arguments as defined by the input schema.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
List containing one or more output values.
|
|
29
|
+
"""
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
def __repr__(self):
|
|
33
|
+
return f"Tool(name={self.name}, description={self.description})"
|
|
34
|
+
|
|
35
|
+
def get_name(self) -> str:
|
|
36
|
+
"""
|
|
37
|
+
Get the name of the tool.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
str: The name of the tool.
|
|
41
|
+
"""
|
|
42
|
+
return self.name
|
|
43
|
+
|
|
44
|
+
def get_description(self) -> str:
|
|
45
|
+
"""
|
|
46
|
+
Get the description of the tool.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
str: The description of the tool.
|
|
50
|
+
"""
|
|
51
|
+
return self.description
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from typing import Dict, List
|
|
2
|
+
from .tool import BaseTool
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BaseToolkit:
|
|
6
|
+
"""
|
|
7
|
+
A Toolkit for managing tools.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self._tools: Dict[str, BaseTool] = {}
|
|
12
|
+
|
|
13
|
+
def add_tool(self, tool: BaseTool) -> None:
|
|
14
|
+
"""
|
|
15
|
+
Add a new tool in the registry.
|
|
16
|
+
|
|
17
|
+
Raises:
|
|
18
|
+
ValueError: If a tool with the same name is already toolkit.
|
|
19
|
+
"""
|
|
20
|
+
if tool.name in self._tools:
|
|
21
|
+
raise ValueError(
|
|
22
|
+
f"Tool with name '{tool.name}' is already present in toolkit."
|
|
23
|
+
)
|
|
24
|
+
self._tools[tool.name] = tool
|
|
25
|
+
|
|
26
|
+
def get_tool(self, name: str) -> BaseTool:
|
|
27
|
+
"""
|
|
28
|
+
Retrieve a tool by its name.
|
|
29
|
+
|
|
30
|
+
Raises:
|
|
31
|
+
ValueError: If no tool with the given name is found.
|
|
32
|
+
"""
|
|
33
|
+
if name not in self._tools:
|
|
34
|
+
raise ValueError(f"Tool with name '{name}' not found.")
|
|
35
|
+
return self._tools[name]
|
|
36
|
+
|
|
37
|
+
def get_all_tools(self) -> List[BaseTool]:
|
|
38
|
+
"""
|
|
39
|
+
List all added tools.
|
|
40
|
+
"""
|
|
41
|
+
return list(self._tools.values())
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from ..api.toolkit import BaseToolkit
|
|
6
|
+
from ..api.tool import BaseTool
|
|
7
|
+
from ..utils.logging import logger_init
|
|
8
|
+
|
|
9
|
+
logger = logger_init("test-toolkit") # Set up logger for the test
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_toolkit():
|
|
13
|
+
"""Test the Toolkit class."""
|
|
14
|
+
|
|
15
|
+
toolkit = BaseToolkit()
|
|
16
|
+
|
|
17
|
+
class DummyTool(BaseTool):
|
|
18
|
+
def __init__(self):
|
|
19
|
+
super().__init__(
|
|
20
|
+
name="dummy_tool",
|
|
21
|
+
description="A dummy tool for testing",
|
|
22
|
+
input_schema={},
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
def call(self, arguments: Dict[str, Any]) -> List[Any]:
|
|
26
|
+
return ["dummy_result"]
|
|
27
|
+
|
|
28
|
+
dummy_tool = DummyTool()
|
|
29
|
+
toolkit.add_tool(dummy_tool)
|
|
30
|
+
|
|
31
|
+
assert toolkit.get_tool("dummy_tool") == dummy_tool
|
|
32
|
+
assert len(toolkit.get_all_tools()) == 1
|
|
33
|
+
|
|
34
|
+
with pytest.raises(ValueError):
|
|
35
|
+
toolkit.add_tool(dummy_tool)
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from ..api.memgraph import Memgraph
|
|
4
|
+
from ..tools.betweenness_centrality import BetweennessCentralityTool
|
|
5
|
+
from ..tools.config import ShowConfigTool
|
|
6
|
+
from ..tools.constraint import ShowConstraintInfoTool
|
|
7
|
+
from ..tools.cypher import CypherTool
|
|
8
|
+
from ..tools.index import ShowIndexInfoTool
|
|
9
|
+
from ..tools.page_rank import PageRankTool
|
|
10
|
+
from ..tools.schema import ShowSchemaInfoTool
|
|
11
|
+
from ..tools.storage import ShowStorageInfoTool
|
|
12
|
+
from ..tools.trigger import ShowTriggersTool
|
|
13
|
+
from ..utils.logging import logger_init
|
|
14
|
+
|
|
15
|
+
logger = logger_init("test-tools")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_show_schema_info_tool():
|
|
19
|
+
"""Test the ShowSchemaInfo tool."""
|
|
20
|
+
|
|
21
|
+
uri = "bolt://localhost:7687"
|
|
22
|
+
user = "memgraph"
|
|
23
|
+
password = "memgraph"
|
|
24
|
+
|
|
25
|
+
memgraph_client = Memgraph(uri=uri, username=user, password=password)
|
|
26
|
+
|
|
27
|
+
schema_tool = ShowSchemaInfoTool(db=memgraph_client)
|
|
28
|
+
assert "show_schema_info" in schema_tool.name
|
|
29
|
+
|
|
30
|
+
result = schema_tool.call({})
|
|
31
|
+
|
|
32
|
+
assert isinstance(result, list)
|
|
33
|
+
assert len(result) >= 1
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_show_config_tool():
|
|
37
|
+
"""Test the ShowConfig tool."""
|
|
38
|
+
|
|
39
|
+
uri = "bolt://localhost:7687"
|
|
40
|
+
user = "memgraph"
|
|
41
|
+
password = "memgraph"
|
|
42
|
+
|
|
43
|
+
memgraph_client = Memgraph(uri=uri, username=user, password=password)
|
|
44
|
+
|
|
45
|
+
config_tool = ShowConfigTool(db=memgraph_client)
|
|
46
|
+
assert "show_config" in config_tool.name
|
|
47
|
+
result = config_tool.call({})
|
|
48
|
+
assert isinstance(result, list)
|
|
49
|
+
assert len(result) >= 1
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_index_tool():
|
|
53
|
+
"""Test the ShowIndexInfo tool."""
|
|
54
|
+
|
|
55
|
+
uri = "bolt://localhost:7687"
|
|
56
|
+
user = "memgraph"
|
|
57
|
+
password = "memgraph"
|
|
58
|
+
|
|
59
|
+
memgraph_client = Memgraph(uri=uri, username=user, password=password)
|
|
60
|
+
|
|
61
|
+
# Create an index for testing
|
|
62
|
+
|
|
63
|
+
memgraph_client.query("CREATE INDEX ON :Person(name)")
|
|
64
|
+
|
|
65
|
+
index_tool = ShowIndexInfoTool(db=memgraph_client)
|
|
66
|
+
assert "show_index_info" in index_tool.name
|
|
67
|
+
result = index_tool.call({})
|
|
68
|
+
|
|
69
|
+
memgraph_client.query("DROP INDEX ON :Person(name)")
|
|
70
|
+
|
|
71
|
+
assert isinstance(result, list)
|
|
72
|
+
|
|
73
|
+
assert len(result) >= 1
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_storage_tool():
|
|
77
|
+
"""Test the ShowStorageInfo tool."""
|
|
78
|
+
|
|
79
|
+
uri = "bolt://localhost:7687"
|
|
80
|
+
user = "memgraph"
|
|
81
|
+
password = "memgraph"
|
|
82
|
+
|
|
83
|
+
memgraph_client = Memgraph(uri=uri, username=user, password=password)
|
|
84
|
+
|
|
85
|
+
storage_tool = ShowStorageInfoTool(db=memgraph_client)
|
|
86
|
+
assert "show_storage_info" in storage_tool.name
|
|
87
|
+
result = storage_tool.call({})
|
|
88
|
+
|
|
89
|
+
assert isinstance(result, list)
|
|
90
|
+
assert len(result) >= 1
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_show_constraint_info_tool():
|
|
94
|
+
"""Test the ShowConstraintInfo tool."""
|
|
95
|
+
uri = "bolt://localhost:7687"
|
|
96
|
+
user = "memgraph"
|
|
97
|
+
password = "memgraph"
|
|
98
|
+
memgraph_client = Memgraph(uri=uri, username=user, password=password)
|
|
99
|
+
# Create a sample constraint
|
|
100
|
+
memgraph_client.query("CREATE CONSTRAINT ON (n:Person) ASSERT n.id IS UNIQUE")
|
|
101
|
+
|
|
102
|
+
constraint_tool = ShowConstraintInfoTool(db=memgraph_client)
|
|
103
|
+
result = constraint_tool.call({})
|
|
104
|
+
|
|
105
|
+
memgraph_client.query("DROP CONSTRAINT ON (n:Person) ASSERT n.id IS UNIQUE")
|
|
106
|
+
|
|
107
|
+
assert isinstance(result, list)
|
|
108
|
+
assert len(result) > 0
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_show_triggers_tool():
|
|
112
|
+
"""Test the ShowTriggers tool."""
|
|
113
|
+
|
|
114
|
+
uri = "bolt://localhost:7687"
|
|
115
|
+
user = "memgraph"
|
|
116
|
+
password = "memgraph"
|
|
117
|
+
memgraph_client = Memgraph(uri=uri, username=user, password=password)
|
|
118
|
+
|
|
119
|
+
memgraph_client.query(
|
|
120
|
+
"""
|
|
121
|
+
CREATE TRIGGER my_trigger ON () CREATE AFTER COMMIT EXECUTE
|
|
122
|
+
UNWIND createdVertices AS newNodes
|
|
123
|
+
SET newNodes.created = timestamp();
|
|
124
|
+
"""
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
trigger_tool = ShowTriggersTool(db=memgraph_client)
|
|
128
|
+
result = trigger_tool.call({})
|
|
129
|
+
|
|
130
|
+
memgraph_client.query("DROP TRIGGER my_trigger;")
|
|
131
|
+
|
|
132
|
+
assert isinstance(result, list)
|
|
133
|
+
assert len(result) > 0
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_page_rank():
|
|
137
|
+
"""Test the PageRank tool."""
|
|
138
|
+
|
|
139
|
+
uri = "bolt://localhost:7687"
|
|
140
|
+
user = "memgraph"
|
|
141
|
+
password = "memgraph"
|
|
142
|
+
memgraph_client = Memgraph(uri=uri, username=user, password=password)
|
|
143
|
+
|
|
144
|
+
# Create a sample graph for testing
|
|
145
|
+
memgraph_client.query(
|
|
146
|
+
"""UNWIND range(1, 10) AS i
|
|
147
|
+
CREATE (:Test {id: i})-[:LINK]->(:Test {id: i + 1});
|
|
148
|
+
"""
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Run the PageRank tool
|
|
152
|
+
page_rank_tool = PageRankTool(db=memgraph_client)
|
|
153
|
+
result = page_rank_tool.call({"limit": 20})
|
|
154
|
+
assert isinstance(result, list)
|
|
155
|
+
assert len(result) > 0
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def test_cypher():
|
|
159
|
+
"""Test the Cypher tool."""
|
|
160
|
+
|
|
161
|
+
uri = "bolt://localhost:7687"
|
|
162
|
+
user = "memgraph"
|
|
163
|
+
password = "memgraph"
|
|
164
|
+
memgraph_client = Memgraph(uri=uri, username=user, password=password)
|
|
165
|
+
|
|
166
|
+
cypher_tool = CypherTool(db=memgraph_client)
|
|
167
|
+
result = cypher_tool.call({"query": "RETURN 0;"})
|
|
168
|
+
assert isinstance(result, list)
|
|
169
|
+
assert len(result) == 1
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_betweenness_centrality_tool():
|
|
173
|
+
"""Test the RunBetweennessCentralityTool."""
|
|
174
|
+
|
|
175
|
+
uri = "bolt://localhost:7687"
|
|
176
|
+
user = "memgraph"
|
|
177
|
+
password = "memgraph"
|
|
178
|
+
memgraph_client = Memgraph(uri=uri, username=user, password=password)
|
|
179
|
+
|
|
180
|
+
memgraph_client.query(
|
|
181
|
+
"""
|
|
182
|
+
UNWIND range(1, 5) AS i
|
|
183
|
+
CREATE (a:Node {id: i})-[:RELATES]->(b:Node {id: i + 1});
|
|
184
|
+
"""
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
betweenness_tool = BetweennessCentralityTool(db=memgraph_client)
|
|
188
|
+
result = betweenness_tool.call({"isDirectionIgnored": True, "limit": 5})
|
|
189
|
+
|
|
190
|
+
assert isinstance(result, list)
|
|
191
|
+
assert len(result) > 0
|
|
192
|
+
assert "node" in result[0]
|
|
193
|
+
assert "betweenness_centrality" in result[0]
|
|
File without changes
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from ..api.memgraph import Memgraph
|
|
4
|
+
from ..api.tool import BaseTool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BetweennessCentralityTool(BaseTool):
|
|
8
|
+
"""
|
|
9
|
+
Tool for calculating betweenness centrality on a graph in Memgraph.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db: Memgraph):
|
|
13
|
+
super().__init__(
|
|
14
|
+
name="run_betweenness_centrality",
|
|
15
|
+
description=(
|
|
16
|
+
"Calculates betweenness centrality for nodes in a graph. "
|
|
17
|
+
"Betweenness centrality measures the importance of a node based on how frequently "
|
|
18
|
+
"it lies on the shortest paths between other nodes, indicating its influence on "
|
|
19
|
+
"information flow within the network."
|
|
20
|
+
),
|
|
21
|
+
input_schema={
|
|
22
|
+
"type": "object",
|
|
23
|
+
"properties": {
|
|
24
|
+
"isDirectionIgnored": {
|
|
25
|
+
"type": "boolean",
|
|
26
|
+
"description": "Set to false to consider the direction of relationships. Default is true.",
|
|
27
|
+
"default": True,
|
|
28
|
+
},
|
|
29
|
+
"limit": {
|
|
30
|
+
"type": "integer",
|
|
31
|
+
"description": "Limit the number of nodes to return. Default is 10.",
|
|
32
|
+
"default": 10,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
"required": [],
|
|
36
|
+
},
|
|
37
|
+
)
|
|
38
|
+
self.db = db
|
|
39
|
+
|
|
40
|
+
def call(self, arguments: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
41
|
+
"""Execute the betweenness centrality algorithm and return the results."""
|
|
42
|
+
is_direction_ignored = arguments.get("isDirectionIgnored", True)
|
|
43
|
+
limit = arguments.get("limit", 10)
|
|
44
|
+
|
|
45
|
+
query = (
|
|
46
|
+
"CALL betweenness_centrality.get($directed, True) "
|
|
47
|
+
"YIELD node, betweenness_centrality "
|
|
48
|
+
"RETURN node, betweenness_centrality "
|
|
49
|
+
"ORDER BY betweenness_centrality DESC "
|
|
50
|
+
"LIMIT $limit"
|
|
51
|
+
)
|
|
52
|
+
params = {"directed": not is_direction_ignored, "limit": limit}
|
|
53
|
+
|
|
54
|
+
results = self.db.query(query, params)
|
|
55
|
+
|
|
56
|
+
# Convert the results to a list of dictionaries
|
|
57
|
+
return results
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from ..api.memgraph import Memgraph
|
|
4
|
+
from ..api.tool import BaseTool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ShowConfigTool(BaseTool):
|
|
8
|
+
"""
|
|
9
|
+
Tool for showing configuration information from Memgraph.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db: Memgraph):
|
|
13
|
+
super().__init__(
|
|
14
|
+
name="show_config",
|
|
15
|
+
description="Shows configuration information from a Memgraph database",
|
|
16
|
+
input_schema={"type": "object", "properties": {}, "required": []},
|
|
17
|
+
)
|
|
18
|
+
self.db = db
|
|
19
|
+
|
|
20
|
+
def call(self, arguments: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
21
|
+
"""Execute the SHOW CONFIG query and return the results."""
|
|
22
|
+
config_info = self.db.query("SHOW CONFIG")
|
|
23
|
+
return config_info
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from ..api.memgraph import Memgraph
|
|
4
|
+
from ..api.tool import BaseTool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ShowConstraintInfoTool(BaseTool):
|
|
8
|
+
"""
|
|
9
|
+
Tool for showing constraint information from Memgraph.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db: Memgraph):
|
|
13
|
+
super().__init__(
|
|
14
|
+
name="show_constraint_info",
|
|
15
|
+
description="Shows constraint information from a Memgraph database",
|
|
16
|
+
input_schema={"type": "object", "properties": {}, "required": []},
|
|
17
|
+
)
|
|
18
|
+
self.db = db
|
|
19
|
+
|
|
20
|
+
def call(self, arguments: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
21
|
+
"""Execute the SHOW CONSTRAINT INFO query and return the results."""
|
|
22
|
+
constraint_info = self.db.query("SHOW CONSTRAINT INFO")
|
|
23
|
+
return constraint_info
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from ..api.memgraph import Memgraph
|
|
4
|
+
from ..api.tool import BaseTool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CypherTool(BaseTool):
|
|
8
|
+
"""
|
|
9
|
+
Tool for running arbitrary Cypher queries on Memgraph.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db: Memgraph):
|
|
13
|
+
super().__init__(
|
|
14
|
+
name="run_cypher",
|
|
15
|
+
description="Executes a Cypher query on a Memgraph database",
|
|
16
|
+
input_schema={
|
|
17
|
+
"type": "object",
|
|
18
|
+
"properties": {
|
|
19
|
+
"query": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"description": "The Cypher query to execute",
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"required": ["query"],
|
|
25
|
+
},
|
|
26
|
+
)
|
|
27
|
+
self.db = db
|
|
28
|
+
|
|
29
|
+
def call(self, arguments: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
30
|
+
"""Execute the provided Cypher query and return the results."""
|
|
31
|
+
query = arguments["query"]
|
|
32
|
+
result = self.db.query(query)
|
|
33
|
+
return [dict(record) for record in result]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from ..api.memgraph import Memgraph
|
|
4
|
+
from ..api.tool import BaseTool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ShowIndexInfoTool(BaseTool):
|
|
8
|
+
"""
|
|
9
|
+
Tool for showing index information in Memgraph.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db: Memgraph):
|
|
13
|
+
super().__init__(
|
|
14
|
+
name="show_index_info",
|
|
15
|
+
description="Shows index information from a Memgraph database",
|
|
16
|
+
input_schema={"type": "object", "properties": {}, "required": []},
|
|
17
|
+
)
|
|
18
|
+
self.db = db
|
|
19
|
+
|
|
20
|
+
def call(self, arguments: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
21
|
+
"""Execute the SHOW INDEX INFO query and return the results."""
|
|
22
|
+
index_info = self.db.query("SHOW INDEX INFO")
|
|
23
|
+
return index_info
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from ..api.memgraph import Memgraph
|
|
4
|
+
from ..api.tool import BaseTool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PageRankTool(BaseTool):
|
|
8
|
+
"""
|
|
9
|
+
Tool for calculating PageRank on a graph in Memgraph.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db: Memgraph):
|
|
13
|
+
super().__init__(
|
|
14
|
+
name="pagerank",
|
|
15
|
+
description="Calculates PageRank on a graph in Memgraph",
|
|
16
|
+
input_schema={
|
|
17
|
+
"type": "object",
|
|
18
|
+
"properties": {
|
|
19
|
+
"limit": {
|
|
20
|
+
"type": "integer",
|
|
21
|
+
"description": "Number of nodes to return ",
|
|
22
|
+
"default": 10,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
"required": [],
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
self.db = db
|
|
29
|
+
|
|
30
|
+
# TODO:(@antejavor) This will fail if user is not running Memgraph Mage since memgraph does not have this built in.
|
|
31
|
+
def call(self, arguments: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
32
|
+
"""Execute the PageRank algorithm and return the results."""
|
|
33
|
+
limit = arguments.get("limit", 20)
|
|
34
|
+
|
|
35
|
+
query = f"""
|
|
36
|
+
CALL pagerank.get()
|
|
37
|
+
YIELD node, rank
|
|
38
|
+
RETURN node, rank
|
|
39
|
+
ORDER BY rank DESC LIMIT {limit}
|
|
40
|
+
"""
|
|
41
|
+
pagerank_results = self.db.query(query)
|
|
42
|
+
|
|
43
|
+
return pagerank_results
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from ..api.memgraph import Memgraph
|
|
4
|
+
from ..api.tool import BaseTool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ShowSchemaInfoTool(BaseTool):
|
|
8
|
+
"""
|
|
9
|
+
Tool for showing schema information from Memgraph.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db: Memgraph):
|
|
13
|
+
super().__init__(
|
|
14
|
+
name="show_schema_info",
|
|
15
|
+
description="Shows schema information from a Memgraph database",
|
|
16
|
+
input_schema={"type": "object", "properties": {}, "required": []},
|
|
17
|
+
)
|
|
18
|
+
self.db = db
|
|
19
|
+
|
|
20
|
+
def call(self, arguments: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
21
|
+
schema_info = self.db.query("SHOW SCHEMA INFO")
|
|
22
|
+
return schema_info
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from ..api.memgraph import Memgraph
|
|
4
|
+
from ..api.tool import BaseTool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ShowStorageInfoTool(BaseTool):
|
|
8
|
+
"""
|
|
9
|
+
Tool for showing storage information from Memgraph.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db: Memgraph):
|
|
13
|
+
super().__init__(
|
|
14
|
+
name="show_storage_info",
|
|
15
|
+
description="Shows storage information from a Memgraph database",
|
|
16
|
+
input_schema={"type": "object", "properties": {}, "required": []},
|
|
17
|
+
)
|
|
18
|
+
self.db = db
|
|
19
|
+
|
|
20
|
+
def call(self, arguments: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
21
|
+
"""Execute the SHOW STORAGE INFO query and return the results."""
|
|
22
|
+
storage_info = self.db.query("SHOW STORAGE INFO")
|
|
23
|
+
return storage_info
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from ..api.memgraph import Memgraph
|
|
4
|
+
from ..api.tool import BaseTool
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ShowTriggersTool(BaseTool):
|
|
8
|
+
"""
|
|
9
|
+
Tool for showing trigger information from Memgraph.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, db: Memgraph):
|
|
13
|
+
super().__init__(
|
|
14
|
+
name="show_triggers",
|
|
15
|
+
description="Shows trigger information from a Memgraph database",
|
|
16
|
+
input_schema={"type": "object", "properties": {}, "required": []},
|
|
17
|
+
)
|
|
18
|
+
self.db = db
|
|
19
|
+
|
|
20
|
+
def call(self, arguments: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
21
|
+
"""Execute the SHOW TRIGGERS query and return the results."""
|
|
22
|
+
trigger_info = self.db.query("SHOW TRIGGERS")
|
|
23
|
+
return trigger_info
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def logger_init(name: str) -> logging.Logger:
|
|
5
|
+
"""Set up a logger with a consistent configuration."""
|
|
6
|
+
logger = logging.getLogger(name)
|
|
7
|
+
if not logger.hasHandlers():
|
|
8
|
+
handler = logging.StreamHandler()
|
|
9
|
+
formatter = logging.Formatter(
|
|
10
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
11
|
+
)
|
|
12
|
+
handler.setFormatter(formatter)
|
|
13
|
+
logger.addHandler(handler)
|
|
14
|
+
logger.setLevel(logging.INFO)
|
|
15
|
+
return logger
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 1
|
|
3
|
+
requires-python = ">=3.13"
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "colorama"
|
|
7
|
+
version = "0.4.6"
|
|
8
|
+
source = { registry = "https://pypi.org/simple" }
|
|
9
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
|
|
10
|
+
wheels = [
|
|
11
|
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "core"
|
|
16
|
+
version = "0.1.0"
|
|
17
|
+
source = { editable = "." }
|
|
18
|
+
|
|
19
|
+
[package.optional-dependencies]
|
|
20
|
+
test = [
|
|
21
|
+
{ name = "pytest" },
|
|
22
|
+
{ name = "pytest-asyncio" },
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[package.metadata]
|
|
26
|
+
requires-dist = [
|
|
27
|
+
{ name = "pytest", marker = "extra == 'test'", specifier = ">=8.3.5" },
|
|
28
|
+
{ name = "pytest-asyncio", marker = "extra == 'test'", specifier = ">=0.26.0" },
|
|
29
|
+
]
|
|
30
|
+
provides-extras = ["test"]
|
|
31
|
+
|
|
32
|
+
[[package]]
|
|
33
|
+
name = "iniconfig"
|
|
34
|
+
version = "2.1.0"
|
|
35
|
+
source = { registry = "https://pypi.org/simple" }
|
|
36
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 }
|
|
37
|
+
wheels = [
|
|
38
|
+
{ url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 },
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[[package]]
|
|
42
|
+
name = "packaging"
|
|
43
|
+
version = "24.2"
|
|
44
|
+
source = { registry = "https://pypi.org/simple" }
|
|
45
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 }
|
|
46
|
+
wheels = [
|
|
47
|
+
{ url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 },
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[[package]]
|
|
51
|
+
name = "pluggy"
|
|
52
|
+
version = "1.5.0"
|
|
53
|
+
source = { registry = "https://pypi.org/simple" }
|
|
54
|
+
sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
|
|
55
|
+
wheels = [
|
|
56
|
+
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[[package]]
|
|
60
|
+
name = "pytest"
|
|
61
|
+
version = "8.3.5"
|
|
62
|
+
source = { registry = "https://pypi.org/simple" }
|
|
63
|
+
dependencies = [
|
|
64
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
65
|
+
{ name = "iniconfig" },
|
|
66
|
+
{ name = "packaging" },
|
|
67
|
+
{ name = "pluggy" },
|
|
68
|
+
]
|
|
69
|
+
sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 }
|
|
70
|
+
wheels = [
|
|
71
|
+
{ url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 },
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[[package]]
|
|
75
|
+
name = "pytest-asyncio"
|
|
76
|
+
version = "0.26.0"
|
|
77
|
+
source = { registry = "https://pypi.org/simple" }
|
|
78
|
+
dependencies = [
|
|
79
|
+
{ name = "pytest" },
|
|
80
|
+
]
|
|
81
|
+
sdist = { url = "https://files.pythonhosted.org/packages/8e/c4/453c52c659521066969523e87d85d54139bbd17b78f09532fb8eb8cdb58e/pytest_asyncio-0.26.0.tar.gz", hash = "sha256:c4df2a697648241ff39e7f0e4a73050b03f123f760673956cf0d72a4990e312f", size = 54156 }
|
|
82
|
+
wheels = [
|
|
83
|
+
{ url = "https://files.pythonhosted.org/packages/20/7f/338843f449ace853647ace35870874f69a764d251872ed1b4de9f234822c/pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0", size = 19694 },
|
|
84
|
+
]
|