Move peo package to a different spot to prepare it for PyPI
This commit is contained in:
1 parent
9a25aa11c9
commit
3e8e498b56
16 files changed
+408
-59
No files matched your search
@@ -3,3 +3,7 @@
|
||||
**/*.pyc
|
||||
.venv
|
||||
tests
|
||||
**/build
|
||||
**/dist
|
||||
**/*.egg-info
|
||||
.idea
|
||||
+219
-2
@@ -1,3 +1,220 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.venv/
|
||||
*.py[codz]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py.cover
|
||||
*.lcov
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
# Pipfile.lock
|
||||
|
||||
# uv
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
# poetry.lock
|
||||
# poetry.toml
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||
# pdm.lock
|
||||
# pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# pixi
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||
# pixi.lock
|
||||
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||
.pixi/*
|
||||
!.pixi/config.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule*
|
||||
celerybeat.pid
|
||||
|
||||
# Redis
|
||||
*.rdb
|
||||
*.aof
|
||||
*.pid
|
||||
|
||||
# RabbitMQ
|
||||
mnesia/
|
||||
rabbitmq/
|
||||
rabbitmq-data/
|
||||
|
||||
# ActiveMQ
|
||||
activemq-data/
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.envrc
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs/Zensical documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
.idea/
|
||||
|
||||
# Abstra
|
||||
# Abstra is an AI-powered process automation framework.
|
||||
# Ignore directories containing user credentials, local state, and settings.
|
||||
# Learn more at https://abstra.io/docs
|
||||
.abstra/
|
||||
|
||||
# Visual Studio Code
|
||||
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that
|
||||
# can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. However, if you prefer, you
|
||||
# could uncomment the following to ignore the entire vscode folder
|
||||
# .vscode/
|
||||
# Temporary file for partial code execution
|
||||
tempCodeRunnerFile.py
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
# Marimo
|
||||
marimo/_static/
|
||||
marimo/_lsp/
|
||||
__marimo__/
|
||||
|
||||
# Streamlit
|
||||
.streamlit/secrets.toml
|
||||
+8
-3
@@ -5,8 +5,8 @@
|
||||
#
|
||||
# Stage 1 builds the neo4j-browser static frontend from source.
|
||||
# Stage 2 is the Apache AGE image (PostgreSQL with the AGE extension) plus the
|
||||
# peo bridge, which speaks the Bolt protocol to the browser and translates
|
||||
# Cypher into AGE `cypher()` calls, and pgAdmin as a SQL interface.
|
||||
# peo Python package, which speaks the Bolt protocol to the browser and
|
||||
# translates Cypher into AGE `cypher()` calls, and pgAdmin as a SQL interface.
|
||||
|
||||
ARG AGE_IMAGE=docker.io/apache/age:release_PG18_1.8.0
|
||||
# Commit of apache/age's release/PG18/1.8.0 branch, for AGE's LICENSE and NOTICE.
|
||||
@@ -59,7 +59,12 @@ ADD https://raw.githubusercontent.com/apache/age/${AGE_SOURCE_REF}/LICENSE \
|
||||
/usr/share/doc/peo/apache-age/
|
||||
|
||||
COPY --from=browser /src/dist /opt/peo/browser
|
||||
COPY bridge /opt/peo/bridge
|
||||
# peo itself, using Debian's psycopg.
|
||||
COPY pyproject.toml README.md LICENSE /tmp/peo/
|
||||
COPY peo /tmp/peo/peo
|
||||
RUN python3 -m venv --system-site-packages /opt/peo/venv \
|
||||
&& /opt/peo/venv/bin/pip install --no-cache-dir --no-deps /tmp/peo \
|
||||
&& rm -r /tmp/peo
|
||||
COPY docker/initdb/ /docker-entrypoint-initdb.d/
|
||||
COPY docker/pgadmin/config_distro.py /opt/peo/pgadmin/config_distro.py
|
||||
COPY docker/peo-entrypoint.sh /usr/local/bin/peo-entrypoint.sh
|
||||
|
||||
@@ -1,57 +1,73 @@
|
||||
# peo
|
||||
|
||||
[neo4j-browser](https://github.com/neo4j/neo4j-browser) running on PostgreSQL, using
|
||||
[Apache AGE](https://github.com/apache/age) as the graph engine.
|
||||
[neo4j-browser](https://github.com/neo4j/neo4j-browser), cypher-shell and the Neo4j
|
||||
drivers on top of PostgreSQL, using [Apache AGE](https://github.com/apache/age) as the
|
||||
graph engine.
|
||||
|
||||
Everything ships in one container image, together with
|
||||
[pgAdmin](https://www.pgadmin.org/) for working with the same data in SQL:
|
||||
peo is a small Python server that speaks Neo4j's Bolt protocol and translates Cypher
|
||||
into AGE `cypher()` calls. It can also serve neo4j-browser. A [container
|
||||
image](#container-image) bundles everything, together with
|
||||
[pgAdmin](https://www.pgadmin.org/) for working with the same data in SQL.
|
||||
|
||||
```
|
||||
neo4j-browser (static files) peo bridge (Python) PostgreSQL + AGE
|
||||
┌──────────────────────┐ Bolt ┌──────────────────────────┐ SQL ┌────────────────┐
|
||||
│ in your web browser │───────▶│ Bolt server (TCP + WS) │──────▶│ cypher('g',$$ │
|
||||
│ served on :7474 │ :7687 │ Cypher → AGE translation │ :5432 │ ... $$) │
|
||||
neo4j-browser (static files) peo (Python) PostgreSQL + AGE
|
||||
┌──────────────────────┐ Bolt ┌────────────────────────-──┐ SQL ┌────────────────┐
|
||||
│ in your web browser │───────▶│ Bolt server (TCP + WS) │──────▶│ cypher('g',$$ │
|
||||
│ served on :7474 │ :7687 │ Cypher → AGE translation │ :5432 │ ... $$) │
|
||||
└──────────────────────┘ │ emulated Neo4j procedures │ └────────────────┘
|
||||
└──────────────────────────┘
|
||||
└─────────────────────────-─┘
|
||||
```
|
||||
|
||||
## Quick start
|
||||
## Installation
|
||||
|
||||
peo needs Python 3.11 or later and a PostgreSQL server with the AGE extension installed
|
||||
and loaded (`shared_preload_libraries=age`).
|
||||
|
||||
```sh
|
||||
podman build -t peo .
|
||||
podman run -d --name peo -e POSTGRES_PASSWORD=secret \
|
||||
-p 7474:7474 -p 7687:7687 -p 5050:5050 -p 5432:5432 \
|
||||
-v peo-data:/var/lib/postgresql -v peo-pgadmin:/var/lib/pgadmin peo
|
||||
pip install 'peo[binary]'
|
||||
PEO_PG_HOST=localhost PEO_PG_DATABASE=postgres peo
|
||||
```
|
||||
|
||||
| Port | Service | Log in with |
|
||||
The `binary` extra pulls in psycopg's prebuilt wheels; leave it out to use a psycopg
|
||||
built against your system's libpq. `python -m peo` works the same as `peo`.
|
||||
|
||||
Neo4j clients can now connect to `neo4j://localhost:7687` with a PostgreSQL user name
|
||||
and password. peo does not include neo4j-browser itself: build it and point
|
||||
`PEO_BROWSER_DIR` at its `dist` directory to serve it on <http://localhost:7474/>, or
|
||||
use the container image.
|
||||
|
||||
## Configuration
|
||||
|
||||
peo is configured through environment variables:
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| 7474 | neo4j-browser: <http://localhost:7474/> | PostgreSQL user `postgres` and `POSTGRES_PASSWORD` |
|
||||
| 7687 | Bolt, for Neo4j drivers and cypher-shell (`neo4j://localhost:7687`) | same as above |
|
||||
| 5050 | pgAdmin: <http://localhost:5050/> | `admin@example.com` and `POSTGRES_PASSWORD` |
|
||||
| 5432 | PostgreSQL, for `psql` and other SQL clients | same as neo4j-browser |
|
||||
|
||||
pgAdmin comes with the bundled PostgreSQL server already registered as "peo";
|
||||
it asks for the PostgreSQL password the first time you open it. AGE stores each
|
||||
graph as a schema of the same name, with one table per label.
|
||||
|
||||
`docker` works as a drop-in replacement for `podman` in the commands above.
|
||||
| `PEO_PG_HOST` | `127.0.0.1` | PostgreSQL host. |
|
||||
| `PEO_PG_PORT` | `5432` | PostgreSQL port. |
|
||||
| `PEO_PG_DATABASE` | `$POSTGRES_DB`, else `$POSTGRES_USER`, else `postgres` | PostgreSQL database holding the graphs. |
|
||||
| `PEO_DEFAULT_GRAPH` | `neo4j` | Graph used when a client does not pick a database. |
|
||||
| `PEO_BOLT_PORT` | `7687` | Port the Bolt server listens on (TCP and WebSocket). |
|
||||
| `PEO_HTTP_PORT` | `7474` | Port neo4j-browser is served on, when `PEO_BROWSER_DIR` is set. |
|
||||
| `PEO_BROWSER_DIR` | (unset) | neo4j-browser `dist` directory to serve. |
|
||||
| `PEO_ADVERTISED_BOLT_PORT` | `$PEO_BOLT_PORT` | Bolt port advertised to the browser; set it when clients reach the Bolt port on another port. |
|
||||
| `PEO_ADVERTISED_HOST` | `localhost` | Host reported in `SHOW DATABASES` and to clients that do not send a routing address. |
|
||||
| `PEO_LOG_LEVEL` | `INFO` | `DEBUG` logs every generated SQL statement. |
|
||||
|
||||
## How it works
|
||||
|
||||
- **Databases are AGE graphs.** Every AGE graph shows up as a Neo4j database, and
|
||||
`:use <name>` switches between them. A graph named `neo4j` is created on first start
|
||||
(`PEO_DEFAULT_GRAPH`). `CREATE DATABASE x` and `DROP DATABASE x` on the `system`
|
||||
`:use <name>` switches between them. Clients that do not pick a database get `PEO_DEFAULT_GRAPH`
|
||||
(`neo4j`); the container image creates that graph on first start. `CREATE DATABASE x` and `DROP DATABASE x` on the `system`
|
||||
database call `create_graph` / `drop_graph`; AGE requires names of at least 3 characters.
|
||||
- **Queries** are sent to AGE as `SELECT * FROM cypher('<graph>', $$ <query> $$) AS (...)`.
|
||||
The bridge works out the result columns from the final `RETURN` clause and inlines
|
||||
peo works out the result columns from the final `RETURN` clause and inlines
|
||||
query parameters as Cypher literals.
|
||||
- **Neo4j procedures** that neo4j-browser relies on (`dbms.components`, `SHOW DATABASES`,
|
||||
`db.labels`, `db.schema.visualization`, `SHOW PROCEDURES`, ...) are emulated from the
|
||||
AGE catalog.
|
||||
- **Workarounds for AGE**: neo4j-browser's "expand node" query uses a pattern
|
||||
comprehension, and its relationship lookup uses `id(n) IN [...]`, which AGE rejects
|
||||
for lists of more than one element. The bridge rewrites both into equivalent Cypher
|
||||
for lists of more than one element. peo rewrites both into equivalent Cypher
|
||||
that AGE accepts.
|
||||
- **Authentication** is passed straight through: every Bolt connection opens its own
|
||||
PostgreSQL connection with the credentials you log in with.
|
||||
@@ -84,16 +100,65 @@ and `REMOVE`, and they can be indexed. Some things to keep in mind:
|
||||
- AGE has no date or time types, so store those as ISO 8601 strings and cast them in
|
||||
SQL.
|
||||
|
||||
## Configuration
|
||||
## Querying the graph from SQL
|
||||
|
||||
AGE stores each node label and relationship type as a table in the graph's schema,
|
||||
with all properties in one `agtype` column, `properties`; `properties ->> 'key'::text`
|
||||
returns a property as text. For typed columns, add them yourself, either as a view or
|
||||
as a generated column:
|
||||
|
||||
```sql
|
||||
CREATE VIEW neo4j.people AS
|
||||
SELECT id, properties ->> 'name'::text AS name, (properties ->> 'age'::text)::bigint AS age
|
||||
FROM neo4j."Person";
|
||||
|
||||
ALTER TABLE neo4j."Person"
|
||||
ADD COLUMN age bigint GENERATED ALWAYS AS ((properties ->> 'age'::text)::bigint) STORED;
|
||||
```
|
||||
|
||||
PostgreSQL keeps generated columns up to date on every Cypher `CREATE`, `MERGE`, `SET`
|
||||
and `REMOVE`, and they can be indexed. Some things to keep in mind:
|
||||
|
||||
- A value that does not fit the column's type makes the Cypher write fail: with the
|
||||
column above, `CREATE (:Person {age: 'old'})` is rejected. A view only fails when it
|
||||
is read.
|
||||
- AGE does not allow dropping columns from its label tables, so a generated column
|
||||
cannot be removed again.
|
||||
- Adding a stored generated column rewrites the table and locks it while doing so.
|
||||
- AGE has no date or time types, so store those as ISO 8601 strings and cast them in
|
||||
SQL.
|
||||
|
||||
## Container image
|
||||
|
||||
The container image runs PostgreSQL with AGE, peo, neo4j-browser and pgAdmin in one
|
||||
container:
|
||||
|
||||
```sh
|
||||
podman build -t peo .
|
||||
podman run -d --name peo -e POSTGRES_PASSWORD=secret \
|
||||
-p 7474:7474 -p 7687:7687 -p 5050:5050 -p 5432:5432 \
|
||||
-v peo-data:/var/lib/postgresql -v peo-pgadmin:/var/lib/pgadmin peo
|
||||
```
|
||||
|
||||
| Port | Service | Log in with |
|
||||
| --- | --- | --- |
|
||||
| 7474 | neo4j-browser: <http://localhost:7474/> | PostgreSQL user `postgres` and `POSTGRES_PASSWORD` |
|
||||
| 7687 | Bolt, for Neo4j drivers and cypher-shell (`neo4j://localhost:7687`) | same as above |
|
||||
| 5050 | pgAdmin: <http://localhost:5050/> | `admin@example.com` and `POSTGRES_PASSWORD` |
|
||||
| 5432 | PostgreSQL, for `psql` and other SQL clients | same as neo4j-browser |
|
||||
|
||||
pgAdmin comes with the bundled PostgreSQL server already registered as "peo";
|
||||
it asks for the PostgreSQL password the first time you open it. AGE stores each
|
||||
graph as a schema of the same name, with one table per label.
|
||||
|
||||
`docker` works as a drop-in replacement for `podman` in the commands above.
|
||||
|
||||
Besides peo's own variables above, the image uses these:
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `POSTGRES_PASSWORD` | (required) | Password of the PostgreSQL superuser, see the [postgres image docs](https://hub.docker.com/_/postgres). `POSTGRES_USER` and `POSTGRES_DB` work too. |
|
||||
| `PEO_DEFAULT_GRAPH` | `neo4j` | Graph created at initialisation and used when a client does not pick a database. |
|
||||
| `PEO_PG_DATABASE` | `$POSTGRES_DB` | PostgreSQL database holding the graphs. |
|
||||
| `PEO_ADVERTISED_BOLT_PORT` | `7687` | Bolt port advertised to the browser; set it when you publish 7687 on another host port. |
|
||||
| `PEO_ADVERTISED_HOST` | `localhost` | Host reported in `SHOW DATABASES` and to clients that do not send a routing address. |
|
||||
| `PEO_LOG_LEVEL` | `INFO` | `DEBUG` logs every generated SQL statement. |
|
||||
| `PEO_DEFAULT_GRAPH` | `neo4j` | Also the graph created when the database is initialised. |
|
||||
| `PGADMIN_DEFAULT_EMAIL` | `admin@example.com` | pgAdmin login, created on first start. |
|
||||
| `PGADMIN_DEFAULT_PASSWORD` | `$POSTGRES_PASSWORD` | pgAdmin login password, set on first start. |
|
||||
| `PEO_PGADMIN` | `true` | Set to `false` to not start pgAdmin. |
|
||||
@@ -117,19 +182,15 @@ This is a first version. Things that do not work (yet):
|
||||
- User and role management, `SHOW TRANSACTIONS`, `:sysinfo`.
|
||||
- TLS (`bolt+s://`, HTTPS).
|
||||
- Each query's full result is fetched from PostgreSQL before it is streamed to the
|
||||
client, so very large results use memory in the bridge.
|
||||
client, so very large results use memory in peo.
|
||||
|
||||
## Development
|
||||
|
||||
The bridge is a dependency-light Python package in [`bridge/peo`](bridge/peo)
|
||||
(only `psycopg` 3). To run it outside the container against any AGE-enabled
|
||||
PostgreSQL:
|
||||
peo's only dependency is `psycopg` 3. To work on it, install it in editable mode;
|
||||
`python -m build` (or `uv build`) builds an sdist and wheel:
|
||||
|
||||
```sh
|
||||
pip install 'psycopg[binary]'
|
||||
cd bridge
|
||||
PEO_PG_HOST=localhost PEO_PG_DATABASE=postgres PEO_BROWSER_DIR=/path/to/neo4j-browser/dist \
|
||||
python -m peo
|
||||
pip install -e '.[binary]'
|
||||
```
|
||||
|
||||
[`tests/smoke_test.py`](tests/smoke_test.py) runs end-to-end checks through the official
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Third-party notices
|
||||
|
||||
peo's own code (the `bridge/`, `docker/` and `tests/` directories and the
|
||||
`Dockerfile`) is licensed under the GNU General Public License v3.0 or later;
|
||||
see [LICENSE](LICENSE).
|
||||
peo's own code (the `peo/`, `docker/` and `tests/` directories, the
|
||||
`Dockerfile` and `pyproject.toml`) is licensed under the GNU General Public
|
||||
License v3.0 or later; see [LICENSE](LICENSE).
|
||||
|
||||
The container image built from this repository also contains the third-party
|
||||
software below. None of it is stored in this repository: it is downloaded when
|
||||
@@ -27,8 +27,8 @@ the image is built. Inside the image, license texts are collected under
|
||||
archive of the exact commit that was built. Its dependencies are pinned by
|
||||
the `yarn.lock` inside that archive, and the build steps are in this
|
||||
repository's `Dockerfile`.
|
||||
- **peo** itself ships as Python source code in `/opt/peo/bridge/`. This
|
||||
repository has the rest.
|
||||
- **peo** itself ships as Python source code in the `/opt/peo/venv/`
|
||||
virtual environment. This repository has the rest.
|
||||
- **Debian packages:** source is available from
|
||||
[sources.debian.org](https://sources.debian.org/) and the Debian archive.
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2026 Bart Broere
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
@@ -40,8 +40,7 @@ EOF
|
||||
docker-entrypoint.sh "$@" &
|
||||
pg_pid=$!
|
||||
|
||||
cd /opt/peo/bridge
|
||||
gosu postgres python3 -m peo &
|
||||
gosu postgres /opt/peo/venv/bin/peo &
|
||||
bridge_pid=$!
|
||||
|
||||
pgadmin_pid=
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-FileCopyrightText: 2026 Bart Broere
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
"""peo: serves neo4j-browser and translates Bolt/Cypher to PostgreSQL + AGE."""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
@@ -1,6 +1,6 @@
|
||||
# SPDX-FileCopyrightText: 2026 Bart Broere
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
"""peo bridge: serves neo4j-browser and translates Bolt/Cypher to PostgreSQL + AGE."""
|
||||
"""peo: serves neo4j-browser and translates Bolt/Cypher to PostgreSQL + AGE."""
|
||||
|
||||
import asyncio
|
||||
import functools
|
||||
@@ -46,8 +46,12 @@ async def main():
|
||||
await asyncio.gather(*(s.serve_forever() for s in servers))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
def run():
|
||||
try:
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,56 @@
|
||||
# SPDX-FileCopyrightText: 2026 Bart Broere
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling>=1.27", "hatch-fancy-pypi-readme>=24.1"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "peo"
|
||||
dynamic = ["version", "readme"]
|
||||
description = "neo4j-browser and Neo4j drivers on top of PostgreSQL, using Apache AGE as the graph engine"
|
||||
license = "GPL-3.0-or-later"
|
||||
license-files = ["LICENSE"]
|
||||
authors = [{ name = "Bart Broere" }]
|
||||
requires-python = ">=3.11"
|
||||
dependencies = ["psycopg>=3.1"]
|
||||
keywords = ["neo4j", "bolt", "cypher", "postgresql", "apache-age", "graph"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Topic :: Database",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
binary = ["psycopg[binary]>=3.1"]
|
||||
|
||||
[project.urls]
|
||||
Source = "https://git.bartbroe.re/bartbroere/peo"
|
||||
|
||||
[project.scripts]
|
||||
peo = "peo.__main__:run"
|
||||
|
||||
[tool.hatch.version]
|
||||
path = "peo/__init__.py"
|
||||
|
||||
[tool.hatch.build.targets.sdist]
|
||||
include = ["/peo", "/README.md", "/LICENSE"]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["peo"]
|
||||
|
||||
# The README links to other files in the repository with relative links, which
|
||||
# do not work on PyPI. Make them absolute in the package metadata only.
|
||||
[tool.hatch.metadata.hooks.fancy-pypi-readme]
|
||||
content-type = "text/markdown"
|
||||
|
||||
[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
|
||||
path = "README.md"
|
||||
|
||||
[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]]
|
||||
pattern = '\]\(#'
|
||||
replacement = '](https://git.bartbroe.re/bartbroere/peo#'
|
||||
|
||||
[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]]
|
||||
pattern = '\]\((?![a-z]+:|#)([^)]+)\)'
|
||||
replacement = '](https://git.bartbroe.re/bartbroere/peo/src/branch/main/\1)'
|
||||
Reference in new issue
Block a user