pyomnigraph 0.2.2__tar.gz → 0.3.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.
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/.github/workflows/build.yml +14 -4
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/.github/workflows/upload-to-pypi.yml +2 -2
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/.project +1 -0
- pyomnigraph-0.3.0/CITATION.cff +31 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/PKG-INFO +40 -25
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/README.md +39 -24
- pyomnigraph-0.3.0/docs/images/ypgen-generator-grid.webp +0 -0
- pyomnigraph-0.3.0/omnigraph/__init__.py +1 -0
- pyomnigraph-0.3.0/omnigraph/compose.py +176 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/omnigraph_cmd.py +28 -1
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/omniserver.py +35 -14
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/rdf_dataset.py +14 -1
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/rdfdump.py +20 -2
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/resources/examples/datasets.yaml +2 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/resources/examples/servers.yaml +31 -5
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/server_config.py +96 -1
- pyomnigraph-0.3.0/omnigraph/servers/allegrograph.py +183 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/servers/blazegraph.py +11 -3
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/servers/graphdb.py +39 -6
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/servers/jena.py +11 -4
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/servers/millenniumdb.py +44 -19
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/servers/oxigraph.py +5 -3
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/servers/qlever.py +52 -9
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/servers/stardog.py +1 -1
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/servers/virtuoso.py +95 -10
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/software.py +11 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/sparql_server.py +245 -27
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/version.py +5 -1
- pyomnigraph-0.3.0/tests/basesparqltest.py +129 -0
- pyomnigraph-0.3.0/tests/test_compose.py +94 -0
- pyomnigraph-0.3.0/tests/test_datasets.py +80 -0
- pyomnigraph-0.3.0/tests/test_examples.py +128 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/tests/test_rdfdump.py +3 -0
- pyomnigraph-0.3.0/tests/test_royals.py +46 -0
- pyomnigraph-0.2.2/omnigraph/__init__.py +0 -1
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/.gitignore +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/.pydevproject +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/AGENTS.md +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/LICENSE +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/docs/index.md +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/mkdocs.yml +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/basecmd.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/ominigraph_paths.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/rdfdump_cmd.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/resources/__init__.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/resources/examples/endpoints.yaml +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/resources/examples/prefixes.yaml +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/resources/examples/queries.yaml +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/resources/examples/royals.ttl +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/omnigraph/servers/__init__.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/pyproject.toml +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/scripts/blackisort +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/scripts/doc +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/scripts/gov-quickstart +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/scripts/install +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/scripts/quickstart +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/scripts/release +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/scripts/test +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/tests/__init__.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/tests/basetest.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/tests/test_omniserver.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/tests/test_qlever.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/tests/test_rdf_dataset_params.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/tests/test_software_list.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/tests/test_sparql_server.py +0 -0
- {pyomnigraph-0.2.2 → pyomnigraph-0.3.0}/tests/test_upload.py +0 -0
|
@@ -18,21 +18,31 @@ jobs:
|
|
|
18
18
|
runs-on: ubuntu-latest
|
|
19
19
|
strategy:
|
|
20
20
|
matrix:
|
|
21
|
-
# os: [ubuntu-latest, macos-latest, windows-latest]
|
|
21
|
+
# os: [ubuntu-latest, macos-latest, windows-latest]
|
|
22
22
|
os: [ubuntu-latest]
|
|
23
|
-
# python-version: [ '3.10', '3.11', '3.12' ]
|
|
23
|
+
# python-version: [ '3.10', '3.11', '3.12', '3.13' ]
|
|
24
24
|
python-version: [ '3.12' ]
|
|
25
25
|
|
|
26
26
|
steps:
|
|
27
|
-
- uses: actions/checkout@
|
|
27
|
+
- uses: actions/checkout@v6
|
|
28
28
|
- name: Set up Python ${{ matrix.python-version }}
|
|
29
|
-
uses: actions/setup-python@
|
|
29
|
+
uses: actions/setup-python@v6
|
|
30
30
|
with:
|
|
31
31
|
python-version: ${{ matrix.python-version }}
|
|
32
|
+
- name: Set up an emulator so images built for another processor family run
|
|
33
|
+
run: |
|
|
34
|
+
docker run --privileged --rm tonistiigi/binfmt --install arm64
|
|
35
|
+
- name: Check out the paper repository for its use case examples
|
|
36
|
+
uses: actions/checkout@v6
|
|
37
|
+
with:
|
|
38
|
+
repository: WolfgangFahl/pyomnigraphPaper
|
|
39
|
+
path: pyomnigraphPaper
|
|
32
40
|
- name: Install python dependencies
|
|
33
41
|
run: |
|
|
34
42
|
python -m pip install --upgrade pip
|
|
35
43
|
scripts/install
|
|
36
44
|
- name: Run tests
|
|
45
|
+
env:
|
|
46
|
+
PYOMNIGRAPH_EXAMPLES: ${{ github.workspace }}/pyomnigraphPaper/examples/railway/dumps
|
|
37
47
|
run: |
|
|
38
48
|
scripts/test
|
|
@@ -11,9 +11,9 @@ jobs:
|
|
|
11
11
|
# IMPORTANT: this permission is mandatory for trusted publishing
|
|
12
12
|
id-token: write
|
|
13
13
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
14
|
+
- uses: actions/checkout@v6
|
|
15
15
|
- name: Set up Python
|
|
16
|
-
uses: actions/setup-python@
|
|
16
|
+
uses: actions/setup-python@v6
|
|
17
17
|
with:
|
|
18
18
|
python-version: '3.x'
|
|
19
19
|
- name: Install dependencies
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# CITATION.cff for https://github.com/WolfgangFahl/pyomnigraph
|
|
2
|
+
# This CITATION.cff file was initially generated with cffinit.
|
|
3
|
+
# Visit https://bit.ly/cffinit to generate yours today!
|
|
4
|
+
cff-version: 1.2.0
|
|
5
|
+
title: pyomnigraph
|
|
6
|
+
message: >-
|
|
7
|
+
If you use this software, please cite it using the
|
|
8
|
+
metadata from this file.
|
|
9
|
+
type: software
|
|
10
|
+
authors:
|
|
11
|
+
- given-names: Wolfgang
|
|
12
|
+
family-names: Fahl
|
|
13
|
+
affiliation: BITPlan GmbH
|
|
14
|
+
orcid: 'https://orcid.org/0000-0002-0821-6995'
|
|
15
|
+
identifiers:
|
|
16
|
+
- type: doi
|
|
17
|
+
value: 10.5281/zenodo.21721772
|
|
18
|
+
description: Concept DOI (all versions) on Zenodo
|
|
19
|
+
repository-code: 'https://github.com/WolfgangFahl/pyomnigraph'
|
|
20
|
+
url: 'https://wiki.bitplan.com/index.php/pyomnigraph'
|
|
21
|
+
abstract: >-
|
|
22
|
+
Unified Python interface for multiple graph databases
|
|
23
|
+
keywords:
|
|
24
|
+
- RDF
|
|
25
|
+
- SPARQL
|
|
26
|
+
- Triple Store
|
|
27
|
+
- Graph Database
|
|
28
|
+
- Docker
|
|
29
|
+
- Wikidata
|
|
30
|
+
- Federated Queries
|
|
31
|
+
license: Apache-2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyomnigraph
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: pyomnigraph: Unified Python interface for multiple graph databases (SPARQL, Neo4j, Weaviate)
|
|
5
5
|
Project-URL: Home, https://github.com/WolfgangFahl/omnigraph
|
|
6
6
|
Project-URL: Documentation, https://wiki.bitplan.com/index.php/omnigraph
|
|
@@ -45,16 +45,29 @@ Requires-Dist: pytest>=7.0.0; extra == 'test'
|
|
|
45
45
|
Description-Content-Type: text/markdown
|
|
46
46
|
|
|
47
47
|
# omnigraph
|
|
48
|
-
|
|
49
|
-
[](https://github.com/WolfgangFahl/pyomnigraph/actions/workflows/build.yml)
|
|
50
|
-
[](https://pypi.python.org/pypi/pyomnigraph/)
|
|
51
|
-
[](https://github.com/WolfgangFahl/pyomnigraph/issues)
|
|
52
|
-
[](https://github.com/WolfgangFahl/pyomnigraph/issues/?q=is%3Aissue+is%3Aclosed)
|
|
53
|
-
[](https://WolfgangFahl.github.io/pyomnigraph/)
|
|
54
|
-
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
48
|
+
Unified Python interface for multiple graph databases
|
|
55
49
|
|
|
50
|
+
| | |
|
|
51
|
+
| :--- | :--- |
|
|
52
|
+
| **PyPi** | [](https://pypi.python.org/pypi/pyomnigraph/) [](https://www.apache.org/licenses/LICENSE-2.0) [](https://pypi.org/project/pyomnigraph/) [](https://pypi.org/project/pyomnigraph/) [](https://pypi.org/project/pyomnigraph/) |
|
|
53
|
+
| **GitHub** | [](https://github.com/WolfgangFahl/pyomnigraph/actions/workflows/build.yml) [](https://github.com/WolfgangFahl/pyomnigraph/releases) [](https://github.com/WolfgangFahl/pyomnigraph/graphs/contributors) [](https://github.com/WolfgangFahl/pyomnigraph/commits/) [](https://github.com/WolfgangFahl/pyomnigraph/issues) [](https://github.com/WolfgangFahl/pyomnigraph/issues/?q=is%3Aissue+is%3Aclosed) |
|
|
54
|
+
| **Code** | [](https://github.com/psf/black) [](https://pycqa.github.io/isort/) |
|
|
55
|
+
| **Docs** | [](https://WolfgangFahl.github.io/pyomnigraph/) [](https://github.com/PyCQA/docformatter) [](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings) |
|
|
56
|
+
| **Cite** | [](https://doi.org/10.5281/zenodo.21721772) |
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
## Cite as
|
|
59
|
+
|
|
60
|
+
If you use pyomnigraph in your research, please cite it via its Zenodo concept DOI
|
|
61
|
+
(which always resolves to the latest version):
|
|
62
|
+
|
|
63
|
+
> Fahl, W.
|
|
64
|
+
> *pyomnigraph — Unified Python interface for multiple graph databases.*
|
|
65
|
+
> Zenodo. https://doi.org/10.5281/zenodo.21721772
|
|
66
|
+
|
|
67
|
+
Machine-readable metadata is available in [`CITATION.cff`](./CITATION.cff);
|
|
68
|
+
GitHub's "Cite this repository" button and Zenodo pick it up automatically.
|
|
69
|
+
For a specific release, use the version DOI shown on the corresponding
|
|
70
|
+
[Zenodo record](https://doi.org/10.5281/zenodo.21721772).
|
|
58
71
|
|
|
59
72
|
## Docs and Tutorials
|
|
60
73
|
[Wiki](https://wiki.bitplan.com/index.php/pyomnigraph)
|
|
@@ -85,31 +98,33 @@ This leads to:
|
|
|
85
98
|
|
|
86
99
|
| Database | Status | Notes |
|
|
87
100
|
|----------|--------|-------|
|
|
88
|
-
| **
|
|
101
|
+
| **AllegroGraph** | 🟢 Working | Multi-model, entity-event knowledge graphs, no license file needed |
|
|
89
102
|
| **Blazegraph** | 🟢 Working | High performance, easy setup |
|
|
103
|
+
| **GraphDB** | 🟢 Working | Enterprise features and reasoning; runs on the free image, empty ruleset |
|
|
104
|
+
| **Apache Jena** | 🟢 Working | Robust, standards compliant |
|
|
105
|
+
| **MillenniumDB** | 🟢 Working | Property Graph + RDF, build-only: the store is produced by mdb import before it can serve |
|
|
90
106
|
| **Oxigraph** | 🟢 Working | Rust-based, embedded, fast |
|
|
91
107
|
| **QLever** | 🟢 Working | Extremely fast queries |
|
|
92
|
-
| **
|
|
93
|
-
| **
|
|
94
|
-
| **Virtuoso** | 🛑 Disabled | Permissions issue (#30) |
|
|
95
|
-
| **Stardog** | 🛑 Planned | License required |
|
|
108
|
+
| **Virtuoso** | 🟢 Working | Mature, SPARQL and SQL over one engine, reasoning and inference, fine grained attribute based access control, SPARQL via SQL |
|
|
109
|
+
| **Stardog** | 🛑 Disabled | License required, knowledge graphs and reasoning |
|
|
96
110
|
|
|
97
111
|
Whether you're building a semantic web application, conducting research, or evaluating different triple stores, pyomnigraph eliminates the complexity of working with multiple graph database systems.
|
|
98
112
|
|
|
99
113
|
## Examples
|
|
100
114
|
```bash
|
|
101
|
-
omnigraph
|
|
115
|
+
omnigraph --list --include-inactive --doc-format github
|
|
102
116
|
```
|
|
103
|
-
| Active | Name
|
|
104
|
-
|
|
105
|
-
| 🟢️ | [
|
|
106
|
-
| 🟢️ | [
|
|
107
|
-
| 🟢️ | [
|
|
108
|
-
| 🟢️ | [
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
117
|
+
| Active | Name | Container Name | Wikidata | Image | Port | Test Port | Dataset | User |
|
|
118
|
+
|----------|----------------------------------------|------------------------|--------------------------------------------------------|--------------------------------------------------------------------------------------------------|--------|-------------|-----------|--------|
|
|
119
|
+
| 🟢️ | [allegrograph](http://localhost:10035) | allegrograph-omnigraph | [Q4731408](https://www.wikidata.org/wiki/Q4731408) | [franzinc/agraph:latest](https://hub.docker.com/r/franzinc/agraph) | 10035 | 10535 | omnigraph | admin |
|
|
120
|
+
| 🟢️ | [blazegraph](http://localhost:9898) | blazegraph-omnigraph | [Q20127748](https://www.wikidata.org/wiki/Q20127748) | [lyrasis/blazegraph:2.1.5](https://hub.docker.com/r/lyrasis/blazegraph) | 9898 | 7898 | kb | |
|
|
121
|
+
| 🟢️ | [graphdb](http://localhost:7200) | graphdb-omnigraph | [Q58425577](https://www.wikidata.org/wiki/Q58425577) | [ontotext/graphdb:11.2.0](https://hub.docker.com/r/ontotext/graphdb) | 7200 | 7700 | repo1 | |
|
|
122
|
+
| 🟢️ | [jena](http://localhost:3030) | jena-omnigraph | [Q109376461](https://www.wikidata.org/wiki/Q109376461) | [stain/jena-fuseki:latest](https://hub.docker.com/r/stain/jena-fuseki) | 3030 | 7030 | ds | admin |
|
|
123
|
+
| 🟢️ | [millenniumdb](http://localhost:1234) | millenniumdb-omnigraph | [Q118954995](https://www.wikidata.org/wiki/Q118954995) | [imfd/millenniumdb](https://hub.docker.com/r/imfd/millenniumdb) | 1234 | 1734 | default | |
|
|
124
|
+
| 🟢️ | [oxigraph](http://localhost:7878) | oxigraph-omnigraph | [Q118980507](https://www.wikidata.org/wiki/Q118980507) | [oxigraph/oxigraph:latest](https://hub.docker.com/r/oxigraph/oxigraph) | 7878 | 7378 | default | |
|
|
125
|
+
| 🟢️ | [qlever](http://localhost:7019) | qlever-omnigraph | [Q111016295](https://www.wikidata.org/wiki/Q111016295) | [adfreiburg/qlever:latest](https://hub.docker.com/r/adfreiburg/qlever) | 7019 | 7819 | olympics | |
|
|
126
|
+
| 🟢️ | [virtuoso](http://localhost:8890) | virtuoso-omnigraph | [Q7935239](https://www.wikidata.org/wiki/Q7935239) | [openlink/virtuoso-opensource-7:latest](https://hub.docker.com/r/openlink/virtuoso-opensource-7) | 8890 | 8390 | KB | dba |
|
|
127
|
+
| 🛑 | [stardog](http://localhost:5820) | stardog-omnigraph | [Q91147741](https://www.wikidata.org/wiki/Q91147741) | [stardog/stardog:latest](https://hub.docker.com/r/stardog/stardog) | 5820 | 5320 | mydb | admin |
|
|
113
128
|
|
|
114
129
|
### Server Management
|
|
115
130
|
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
# omnigraph
|
|
2
|
-
|
|
3
|
-
[](https://github.com/WolfgangFahl/pyomnigraph/actions/workflows/build.yml)
|
|
4
|
-
[](https://pypi.python.org/pypi/pyomnigraph/)
|
|
5
|
-
[](https://github.com/WolfgangFahl/pyomnigraph/issues)
|
|
6
|
-
[](https://github.com/WolfgangFahl/pyomnigraph/issues/?q=is%3Aissue+is%3Aclosed)
|
|
7
|
-
[](https://WolfgangFahl.github.io/pyomnigraph/)
|
|
8
|
-
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
2
|
+
Unified Python interface for multiple graph databases
|
|
9
3
|
|
|
4
|
+
| | |
|
|
5
|
+
| :--- | :--- |
|
|
6
|
+
| **PyPi** | [](https://pypi.python.org/pypi/pyomnigraph/) [](https://www.apache.org/licenses/LICENSE-2.0) [](https://pypi.org/project/pyomnigraph/) [](https://pypi.org/project/pyomnigraph/) [](https://pypi.org/project/pyomnigraph/) |
|
|
7
|
+
| **GitHub** | [](https://github.com/WolfgangFahl/pyomnigraph/actions/workflows/build.yml) [](https://github.com/WolfgangFahl/pyomnigraph/releases) [](https://github.com/WolfgangFahl/pyomnigraph/graphs/contributors) [](https://github.com/WolfgangFahl/pyomnigraph/commits/) [](https://github.com/WolfgangFahl/pyomnigraph/issues) [](https://github.com/WolfgangFahl/pyomnigraph/issues/?q=is%3Aissue+is%3Aclosed) |
|
|
8
|
+
| **Code** | [](https://github.com/psf/black) [](https://pycqa.github.io/isort/) |
|
|
9
|
+
| **Docs** | [](https://WolfgangFahl.github.io/pyomnigraph/) [](https://github.com/PyCQA/docformatter) [](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings) |
|
|
10
|
+
| **Cite** | [](https://doi.org/10.5281/zenodo.21721772) |
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
## Cite as
|
|
13
|
+
|
|
14
|
+
If you use pyomnigraph in your research, please cite it via its Zenodo concept DOI
|
|
15
|
+
(which always resolves to the latest version):
|
|
16
|
+
|
|
17
|
+
> Fahl, W.
|
|
18
|
+
> *pyomnigraph — Unified Python interface for multiple graph databases.*
|
|
19
|
+
> Zenodo. https://doi.org/10.5281/zenodo.21721772
|
|
20
|
+
|
|
21
|
+
Machine-readable metadata is available in [`CITATION.cff`](./CITATION.cff);
|
|
22
|
+
GitHub's "Cite this repository" button and Zenodo pick it up automatically.
|
|
23
|
+
For a specific release, use the version DOI shown on the corresponding
|
|
24
|
+
[Zenodo record](https://doi.org/10.5281/zenodo.21721772).
|
|
12
25
|
|
|
13
26
|
## Docs and Tutorials
|
|
14
27
|
[Wiki](https://wiki.bitplan.com/index.php/pyomnigraph)
|
|
@@ -39,31 +52,33 @@ This leads to:
|
|
|
39
52
|
|
|
40
53
|
| Database | Status | Notes |
|
|
41
54
|
|----------|--------|-------|
|
|
42
|
-
| **
|
|
55
|
+
| **AllegroGraph** | 🟢 Working | Multi-model, entity-event knowledge graphs, no license file needed |
|
|
43
56
|
| **Blazegraph** | 🟢 Working | High performance, easy setup |
|
|
57
|
+
| **GraphDB** | 🟢 Working | Enterprise features and reasoning; runs on the free image, empty ruleset |
|
|
58
|
+
| **Apache Jena** | 🟢 Working | Robust, standards compliant |
|
|
59
|
+
| **MillenniumDB** | 🟢 Working | Property Graph + RDF, build-only: the store is produced by mdb import before it can serve |
|
|
44
60
|
| **Oxigraph** | 🟢 Working | Rust-based, embedded, fast |
|
|
45
61
|
| **QLever** | 🟢 Working | Extremely fast queries |
|
|
46
|
-
| **
|
|
47
|
-
| **
|
|
48
|
-
| **Virtuoso** | 🛑 Disabled | Permissions issue (#30) |
|
|
49
|
-
| **Stardog** | 🛑 Planned | License required |
|
|
62
|
+
| **Virtuoso** | 🟢 Working | Mature, SPARQL and SQL over one engine, reasoning and inference, fine grained attribute based access control, SPARQL via SQL |
|
|
63
|
+
| **Stardog** | 🛑 Disabled | License required, knowledge graphs and reasoning |
|
|
50
64
|
|
|
51
65
|
Whether you're building a semantic web application, conducting research, or evaluating different triple stores, pyomnigraph eliminates the complexity of working with multiple graph database systems.
|
|
52
66
|
|
|
53
67
|
## Examples
|
|
54
68
|
```bash
|
|
55
|
-
omnigraph
|
|
69
|
+
omnigraph --list --include-inactive --doc-format github
|
|
56
70
|
```
|
|
57
|
-
| Active | Name
|
|
58
|
-
|
|
59
|
-
| 🟢️ | [
|
|
60
|
-
| 🟢️ | [
|
|
61
|
-
| 🟢️ | [
|
|
62
|
-
| 🟢️ | [
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
71
|
+
| Active | Name | Container Name | Wikidata | Image | Port | Test Port | Dataset | User |
|
|
72
|
+
|----------|----------------------------------------|------------------------|--------------------------------------------------------|--------------------------------------------------------------------------------------------------|--------|-------------|-----------|--------|
|
|
73
|
+
| 🟢️ | [allegrograph](http://localhost:10035) | allegrograph-omnigraph | [Q4731408](https://www.wikidata.org/wiki/Q4731408) | [franzinc/agraph:latest](https://hub.docker.com/r/franzinc/agraph) | 10035 | 10535 | omnigraph | admin |
|
|
74
|
+
| 🟢️ | [blazegraph](http://localhost:9898) | blazegraph-omnigraph | [Q20127748](https://www.wikidata.org/wiki/Q20127748) | [lyrasis/blazegraph:2.1.5](https://hub.docker.com/r/lyrasis/blazegraph) | 9898 | 7898 | kb | |
|
|
75
|
+
| 🟢️ | [graphdb](http://localhost:7200) | graphdb-omnigraph | [Q58425577](https://www.wikidata.org/wiki/Q58425577) | [ontotext/graphdb:11.2.0](https://hub.docker.com/r/ontotext/graphdb) | 7200 | 7700 | repo1 | |
|
|
76
|
+
| 🟢️ | [jena](http://localhost:3030) | jena-omnigraph | [Q109376461](https://www.wikidata.org/wiki/Q109376461) | [stain/jena-fuseki:latest](https://hub.docker.com/r/stain/jena-fuseki) | 3030 | 7030 | ds | admin |
|
|
77
|
+
| 🟢️ | [millenniumdb](http://localhost:1234) | millenniumdb-omnigraph | [Q118954995](https://www.wikidata.org/wiki/Q118954995) | [imfd/millenniumdb](https://hub.docker.com/r/imfd/millenniumdb) | 1234 | 1734 | default | |
|
|
78
|
+
| 🟢️ | [oxigraph](http://localhost:7878) | oxigraph-omnigraph | [Q118980507](https://www.wikidata.org/wiki/Q118980507) | [oxigraph/oxigraph:latest](https://hub.docker.com/r/oxigraph/oxigraph) | 7878 | 7378 | default | |
|
|
79
|
+
| 🟢️ | [qlever](http://localhost:7019) | qlever-omnigraph | [Q111016295](https://www.wikidata.org/wiki/Q111016295) | [adfreiburg/qlever:latest](https://hub.docker.com/r/adfreiburg/qlever) | 7019 | 7819 | olympics | |
|
|
80
|
+
| 🟢️ | [virtuoso](http://localhost:8890) | virtuoso-omnigraph | [Q7935239](https://www.wikidata.org/wiki/Q7935239) | [openlink/virtuoso-opensource-7:latest](https://hub.docker.com/r/openlink/virtuoso-opensource-7) | 8890 | 8390 | KB | dba |
|
|
81
|
+
| 🛑 | [stardog](http://localhost:5820) | stardog-omnigraph | [Q91147741](https://www.wikidata.org/wiki/Q91147741) | [stardog/stardog:latest](https://hub.docker.com/r/stardog/stardog) | 5820 | 5320 | mydb | admin |
|
|
67
82
|
|
|
68
83
|
### Server Management
|
|
69
84
|
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.0"
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Created on 2026-08-05
|
|
3
|
+
|
|
4
|
+
docker compose generation from the server configurations - see issue #29
|
|
5
|
+
|
|
6
|
+
@author: wf
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import shlex
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
import yaml
|
|
14
|
+
|
|
15
|
+
from omnigraph.server_config import ServerConfig
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class ComposeService:
|
|
20
|
+
"""
|
|
21
|
+
one service of a docker compose file
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
image: str
|
|
25
|
+
container_name: str
|
|
26
|
+
ports: List[str] = field(default_factory=list)
|
|
27
|
+
volumes: List[str] = field(default_factory=list)
|
|
28
|
+
environment: List[str] = field(default_factory=list)
|
|
29
|
+
command: Optional[str] = None
|
|
30
|
+
platform: Optional[str] = None
|
|
31
|
+
user: Optional[str] = None
|
|
32
|
+
shm_size: Optional[str] = None
|
|
33
|
+
|
|
34
|
+
def as_dict(self) -> Dict:
|
|
35
|
+
"""
|
|
36
|
+
Get the compose representation.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
dict of the compose keys that are set
|
|
40
|
+
"""
|
|
41
|
+
service = {"image": self.image, "container_name": self.container_name}
|
|
42
|
+
if self.platform:
|
|
43
|
+
service["platform"] = self.platform
|
|
44
|
+
if self.user:
|
|
45
|
+
service["user"] = self.user
|
|
46
|
+
if self.shm_size:
|
|
47
|
+
service["shm_size"] = self.shm_size
|
|
48
|
+
if self.ports:
|
|
49
|
+
service["ports"] = self.ports
|
|
50
|
+
if self.volumes:
|
|
51
|
+
service["volumes"] = self.volumes
|
|
52
|
+
if self.environment:
|
|
53
|
+
service["environment"] = self.environment
|
|
54
|
+
if self.command:
|
|
55
|
+
service["command"] = self.command
|
|
56
|
+
service["restart"] = "unless-stopped"
|
|
57
|
+
return service
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ComposeGenerator:
|
|
61
|
+
"""
|
|
62
|
+
Generate a docker compose file from the docker run commands of the server
|
|
63
|
+
configurations, so that the compose file and the CLI cannot drift apart.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(self, project_name: str = "omnigraph"):
|
|
67
|
+
"""
|
|
68
|
+
Initialize the generator.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
project_name: name of the compose project
|
|
72
|
+
"""
|
|
73
|
+
self.project_name = project_name
|
|
74
|
+
|
|
75
|
+
def service_of_run_command(self, run_command: str) -> ComposeService:
|
|
76
|
+
"""
|
|
77
|
+
Translate a docker run command into a compose service.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
run_command: the complete docker run command
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
the ComposeService or None if the command can not be translated
|
|
84
|
+
"""
|
|
85
|
+
service = None
|
|
86
|
+
tokens = shlex.split(run_command)
|
|
87
|
+
if len(tokens) > 2 and tokens[0] == "docker" and tokens[1] == "run":
|
|
88
|
+
tokens = tokens[2:]
|
|
89
|
+
ports = []
|
|
90
|
+
volumes = []
|
|
91
|
+
environment = []
|
|
92
|
+
platform = None
|
|
93
|
+
user = None
|
|
94
|
+
shm_size = None
|
|
95
|
+
image = None
|
|
96
|
+
container_name = None
|
|
97
|
+
command_parts = []
|
|
98
|
+
index = 0
|
|
99
|
+
while index < len(tokens):
|
|
100
|
+
token = tokens[index]
|
|
101
|
+
if image is not None:
|
|
102
|
+
command_parts.append(token)
|
|
103
|
+
elif token in ("-d", "--rm", "--init"):
|
|
104
|
+
pass
|
|
105
|
+
elif token == "--name":
|
|
106
|
+
index += 1
|
|
107
|
+
container_name = tokens[index]
|
|
108
|
+
elif token in ("-e", "--env"):
|
|
109
|
+
index += 1
|
|
110
|
+
environment.append(tokens[index])
|
|
111
|
+
elif token in ("-p", "--publish"):
|
|
112
|
+
index += 1
|
|
113
|
+
ports.append(tokens[index])
|
|
114
|
+
elif token in ("-v", "--volume"):
|
|
115
|
+
index += 1
|
|
116
|
+
volumes.append(tokens[index])
|
|
117
|
+
elif token == "--platform":
|
|
118
|
+
index += 1
|
|
119
|
+
platform = tokens[index]
|
|
120
|
+
elif token in ("-u", "--user"):
|
|
121
|
+
index += 1
|
|
122
|
+
user = tokens[index]
|
|
123
|
+
elif token == "--shm-size":
|
|
124
|
+
index += 1
|
|
125
|
+
shm_size = tokens[index]
|
|
126
|
+
elif token.startswith("-"):
|
|
127
|
+
# unknown flag with a value, e.g. --restart=x is self contained
|
|
128
|
+
if "=" not in token and index + 1 < len(tokens) and not tokens[index + 1].startswith("-"):
|
|
129
|
+
index += 1
|
|
130
|
+
else:
|
|
131
|
+
image = token
|
|
132
|
+
index += 1
|
|
133
|
+
if image and container_name:
|
|
134
|
+
service = ComposeService(
|
|
135
|
+
image=image,
|
|
136
|
+
container_name=container_name,
|
|
137
|
+
ports=ports,
|
|
138
|
+
volumes=volumes,
|
|
139
|
+
environment=environment,
|
|
140
|
+
command=" ".join(command_parts) if command_parts else None,
|
|
141
|
+
platform=platform,
|
|
142
|
+
user=user,
|
|
143
|
+
shm_size=shm_size,
|
|
144
|
+
)
|
|
145
|
+
return service
|
|
146
|
+
|
|
147
|
+
def as_compose(self, configs: Dict[str, ServerConfig], data_dir_of) -> str:
|
|
148
|
+
"""
|
|
149
|
+
Generate the compose file for the given server configurations.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
configs: server name to ServerConfig
|
|
153
|
+
data_dir_of: callable returning the data directory of a config
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
the compose file as yaml
|
|
157
|
+
"""
|
|
158
|
+
services = {}
|
|
159
|
+
skipped = []
|
|
160
|
+
for name, config in configs.items():
|
|
161
|
+
run_command = None
|
|
162
|
+
try:
|
|
163
|
+
run_command = config.get_docker_run_command(data_dir=data_dir_of(config))
|
|
164
|
+
except Exception:
|
|
165
|
+
run_command = None
|
|
166
|
+
service = self.service_of_run_command(run_command) if run_command else None
|
|
167
|
+
if service:
|
|
168
|
+
services[name] = service.as_dict()
|
|
169
|
+
else:
|
|
170
|
+
skipped.append(name)
|
|
171
|
+
compose = {"name": self.project_name, "services": services}
|
|
172
|
+
markup = yaml.dump(compose, sort_keys=False, default_flow_style=False)
|
|
173
|
+
if skipped:
|
|
174
|
+
names = ", ".join(sorted(skipped))
|
|
175
|
+
markup += f"\n# not expressible as a compose service: {names}\n"
|
|
176
|
+
return markup
|
|
@@ -11,6 +11,7 @@ from typing import Dict, List
|
|
|
11
11
|
from lodstorage.prefix_config import PrefixConfigs
|
|
12
12
|
|
|
13
13
|
from omnigraph.basecmd import BaseCmd
|
|
14
|
+
from omnigraph.compose import ComposeGenerator
|
|
14
15
|
from omnigraph.ominigraph_paths import OmnigraphPaths
|
|
15
16
|
from omnigraph.omniserver import OmniServer
|
|
16
17
|
from omnigraph.rdf_dataset import RdfDataset
|
|
@@ -71,6 +72,11 @@ class OmnigraphCmd(BaseCmd):
|
|
|
71
72
|
parser.add_argument(
|
|
72
73
|
"-l", "--list-servers", action="store_true", help="List available servers [default: %(default)s]"
|
|
73
74
|
)
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
"--compose",
|
|
77
|
+
action="store_true",
|
|
78
|
+
help="generate a docker compose file for the servers [default: %(default)s]",
|
|
79
|
+
)
|
|
74
80
|
parser.add_argument(
|
|
75
81
|
"--test",
|
|
76
82
|
action="store_true",
|
|
@@ -98,7 +104,16 @@ class OmnigraphCmd(BaseCmd):
|
|
|
98
104
|
servers = {}
|
|
99
105
|
server_names = self.args.servers
|
|
100
106
|
if "all" in server_names:
|
|
101
|
-
|
|
107
|
+
# all means all that can run on this machine - see #61; an explicitly
|
|
108
|
+
# named server is still tried and reports what it lacks
|
|
109
|
+
server_names = []
|
|
110
|
+
for name, candidate in self.all_servers.items():
|
|
111
|
+
support = candidate.config.support_status
|
|
112
|
+
if support.can_start():
|
|
113
|
+
server_names.append(name)
|
|
114
|
+
else:
|
|
115
|
+
unmet = ", ".join(candidate.config.unmet_prerequisites()) or support.value
|
|
116
|
+
self.log.log("🛑", "omnigraph", f"skipping {name}: {unmet}")
|
|
102
117
|
for server_name in server_names:
|
|
103
118
|
server = self.all_servers.get(server_name)
|
|
104
119
|
if server:
|
|
@@ -220,6 +235,18 @@ class OmnigraphCmd(BaseCmd):
|
|
|
220
235
|
config = server.config
|
|
221
236
|
print(config.to_apache_config(version=self.version, domain=self.args.apache))
|
|
222
237
|
|
|
238
|
+
if self.args.compose:
|
|
239
|
+
compose_generator = ComposeGenerator()
|
|
240
|
+
# the whole stack, not the -s selection, with a data directory derived
|
|
241
|
+
# per server - relying on the side effects of server selection left a
|
|
242
|
+
# None volume in the file, found trying it out on fur
|
|
243
|
+
configs = {name: server.config for name, server in self.all_servers.items()}
|
|
244
|
+
markup = compose_generator.as_compose(
|
|
245
|
+
configs,
|
|
246
|
+
lambda config: config.base_data_dir or str(self.ogp.omnigraph_dir / config.name / "data"),
|
|
247
|
+
)
|
|
248
|
+
print(markup)
|
|
249
|
+
|
|
223
250
|
if self.args.list_servers:
|
|
224
251
|
table_format = self.args.doc_format if self.args.doc_format != "plain" else "simple"
|
|
225
252
|
markup = self.omni_server.list_servers(self.all_servers, table_format)
|
|
@@ -12,7 +12,8 @@ from lodstorage.prefix_config import PrefixConfigs
|
|
|
12
12
|
from tabulate import tabulate
|
|
13
13
|
|
|
14
14
|
from omnigraph.ominigraph_paths import OmnigraphPaths
|
|
15
|
-
from omnigraph.server_config import ServerCmd, ServerConfig, ServerConfigs, ServerEnv
|
|
15
|
+
from omnigraph.server_config import LoadPath, ServerCmd, ServerConfig, ServerConfigs, ServerEnv
|
|
16
|
+
from omnigraph.servers.allegrograph import AllegroGraph, AllegroGraphConfig
|
|
16
17
|
from omnigraph.servers.blazegraph import Blazegraph, BlazegraphConfig
|
|
17
18
|
from omnigraph.servers.graphdb import GraphDB, GraphDBConfig
|
|
18
19
|
from omnigraph.servers.jena import Jena, JenaConfig
|
|
@@ -64,6 +65,18 @@ class OmniServer:
|
|
|
64
65
|
"count": lambda s: ServerCmd(title("triple count", s), s.count_triples),
|
|
65
66
|
"info": lambda s: ServerCmd(title("info", s), s.docker_info),
|
|
66
67
|
"load": lambda s: ServerCmd(title("load dumps", s), s.load_dump_files),
|
|
68
|
+
"liveload": lambda s: ServerCmd(
|
|
69
|
+
title("liveload dumps into the running server", s),
|
|
70
|
+
lambda: s.load_dump_files(path=LoadPath.LIVELOAD),
|
|
71
|
+
),
|
|
72
|
+
"bulkload": lambda s: ServerCmd(
|
|
73
|
+
title("bulkload dumps with the native loader", s),
|
|
74
|
+
lambda: s.load_dump_files(path=LoadPath.BULKLOAD),
|
|
75
|
+
),
|
|
76
|
+
"build": lambda s: ServerCmd(
|
|
77
|
+
title("build the store from the dumps", s),
|
|
78
|
+
lambda: s.load_dump_files(path=LoadPath.BUILD),
|
|
79
|
+
),
|
|
67
80
|
"logs": lambda s: ServerCmd(title("logs of", s), s.logs),
|
|
68
81
|
"needed": lambda s: ServerCmd(title("check needed software for", s), s.check_needed_software),
|
|
69
82
|
"rm": lambda s: ServerCmd(title("remove", s), s.rm),
|
|
@@ -90,6 +103,7 @@ class OmniServer:
|
|
|
90
103
|
config_dict = asdict(config)
|
|
91
104
|
|
|
92
105
|
server_mappings = {
|
|
106
|
+
"allegrograph": (AllegroGraphConfig, AllegroGraph),
|
|
93
107
|
"blazegraph": (BlazegraphConfig, Blazegraph),
|
|
94
108
|
"graphdb": (GraphDBConfig, GraphDB),
|
|
95
109
|
"jena": (JenaConfig, Jena),
|
|
@@ -161,7 +175,9 @@ class OmniServer:
|
|
|
161
175
|
else:
|
|
162
176
|
return text
|
|
163
177
|
|
|
164
|
-
|
|
178
|
+
# active servers first, then alphabetically - the config order is not meaningful
|
|
179
|
+
sorted_servers = sorted(servers.values(), key=lambda s: (not s.config.active, s.name))
|
|
180
|
+
for server in sorted_servers:
|
|
165
181
|
active_str = server.flag
|
|
166
182
|
|
|
167
183
|
wikidata_id = getattr(server.config, "wikidata_id", "")
|
|
@@ -218,24 +234,29 @@ class OmniServer:
|
|
|
218
234
|
auth = "\n auth: BASIC" if server.config.auth_user else ""
|
|
219
235
|
user = f"\n user: {server.config.auth_user}" if server.config.auth_user else ""
|
|
220
236
|
passwd = f"\n passwd: {server.config.auth_password}" if server.config.auth_password else ""
|
|
221
|
-
# Indent prefixes for literal block scalar (
|
|
222
|
-
indented_prefixes = "\n".join(f"
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
237
|
+
# Indent prefixes for literal block scalar (6 spaces below the endpoints: wrapper)
|
|
238
|
+
indented_prefixes = "\n".join(f" {line}" for line in prefixes_text.split("\n") if line.strip())
|
|
239
|
+
# optional elements indented for the endpoints: wrapper
|
|
240
|
+
auth = auth.replace("\n ", "\n ")
|
|
241
|
+
user = user.replace("\n ", "\n ")
|
|
242
|
+
passwd = passwd.replace("\n ", "\n ")
|
|
243
|
+
|
|
244
|
+
# entry below the endpoints: wrapper lodstorage EndpointManager expects - see issue #39
|
|
245
|
+
entry = f""" {server.name}:
|
|
246
|
+
method: {getattr(server.config, 'method', 'POST')}
|
|
247
|
+
lang: sparql
|
|
248
|
+
name: {server.name}
|
|
249
|
+
endpoint: {server.config.sparql_url}
|
|
250
|
+
website: {server.config.base_url}
|
|
251
|
+
database: {server.config.server}{auth}{user}{passwd}
|
|
252
|
+
prefixes: |
|
|
232
253
|
{indented_prefixes}"""
|
|
233
254
|
|
|
234
255
|
yaml_entries.append(entry)
|
|
235
256
|
|
|
236
257
|
yaml_header = "# SPARQL endpoints for snapquery, sparqlquery and omnigraph tools\n"
|
|
237
258
|
yaml_header += server.config.generator_header() + "\n"
|
|
238
|
-
yaml_content = yaml_header + "\n".join(yaml_entries)
|
|
259
|
+
yaml_content = yaml_header + "endpoints:\n" + "\n".join(yaml_entries)
|
|
239
260
|
|
|
240
261
|
if output_path:
|
|
241
262
|
with open(output_path, "w") as f:
|