Metadata-Version: 2.1
Name: neug
Version: 0.1.3
Summary: GraphScope NeuG for python
Home-page: https://github.com/alibaba/neug
Author: GraphScope Team
Author-email: GraphScope Team <graphscope@alibaba-inc.com>
License: Apache License 2.0
Keywords: Graph,Python,Embedded,Graph Database
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Topic :: Software Development :: Libraries
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: packaging>=24.2
Requires-Dist: protobuf==5.29.6
Requires-Dist: requests
Requires-Dist: click>=8.0.0
Requires-Dist: prompt-toolkit>=3.0.0
Requires-Dist: tabulate>=0.9.0
Requires-Dist: PyYAML>=6.0.2
Requires-Dist: tqdm
Requires-Dist: Flask
Requires-Dist: Flask-Cors
Provides-Extra: test
Requires-Dist: pytest>=6.2.5; extra == "test"
Requires-Dist: black>=23.3.0; extra == "test"
Requires-Dist: flake8==4.0.1; extra == "test"
Requires-Dist: isort==5.10.1; extra == "test"

# The python binding API for NeuG

## Architecture

The Python binding (`neug_py_bind*.so`) dynamically links against the core
shared library `libneug.{dylib,so}` produced by the root CMake build.
Both bindings and core are built in the **same** root build tree
(`<repo>/build/`); the Python flow consumes those artifacts rather than
re-running a separate CMake configure.

```
<repo>/build/                          # single root build tree
├── src/libneug.{dylib,so}             # core (shared)
└── tools/python_bind/
    └── neug_py_bind.<abi>.so          # binding, RPATH → core
```

Future bindings (Node, Rust, …) follow the same pattern: their `.so` lives
under `build/tools/<binding>/` and link against the same `libneug`.

## Development

### Setup

```bash
cd tools/python_bind
make requirements    # one-time: install Python deps
make dev             # incremental rebuild of neug_py_bind; auto-bootstraps
                     # the root build on first run or if it wasn't configured
                     # with -DBUILD_PYTHON=ON
```

`make dev-full` is also available if you want to force a full reconfigure
(equivalent to `cmake -S <repo> -B <repo>/build -DBUILD_PYTHON=ON && cmake --build ...`).

### Dev loop

```bash
# After editing C++ binding sources or core
make dev          # incremental rebuild of neug_py_bind only (seconds)

# After editing only Python sources (neug/*.py): no rebuild needed,
# editable import works because the loader auto-finds the .so in
# <repo>/build/tools/python_bind/.

python3 -m pytest -s tests/test_db_query.py
```

The `neug/__init__.py` loader resolves `neug_py_bind*.so` in this order:
1. The `neug/` package directory itself (wheel-installed layout).
2. `$NEUG_BUILD_DIR/tools/python_bind/` (default `<repo>/build/...`).
3. Legacy `tools/python_bind/build/lib.<plat>-cpython-*` (back-compat fallback).

So you can point at an out-of-tree build via `NEUG_BUILD_DIR=/path/to/build`.

### Building the Wheel

```bash
make wheel        # produces dist/neug-*.whl
```

`make wheel` reuses the root build (creating it on the fly via the `setup.py`
fallback if absent). The wheel bundles both `neug_py_bind*.so` and
`libneug.{dylib,so}` into the `neug` package; they find each other at runtime
via `@loader_path` (macOS) / `$ORIGIN` (Linux) RPATH.

## Python service API

`Database.serve()` starts the database in service mode and can configure the service thread count:

```python
from neug import Database

db = Database("/path/to/database", mode="rw")
endpoint = db.serve(
    host="0.0.0.0",
    port=10000,
    blocking=False,
    thread_num=0,
)
```

`thread_num=0` is the default and auto-selects from the database
`max_thread_num`. If set explicitly, it must be less than or equal to that
value. With the default database thread setting, `max_thread_num` is resolved
from hardware concurrency and falls back to `1` if the runtime cannot detect it.
This is separate from client-side `Session(..., num_threads=...)`, which
configures the client's HTTP connection pool.

### Multi-version wheels via cibuildwheel

```bash
python3 -m pip install cibuildwheel
cd <repo>
cibuildwheel ./tools/python_bind --output-dir wheelhouse
```

Cibuildwheel runs in fresh manylinux/macOS containers; `setup.py` detects no
pre-existing root build and falls back to running cmake configure in
`<repo>/build/` inside the container, then builds only the `neug_py_bind`
target. No changes to `pyproject.toml` are needed.

### Clean

```bash
make clean        # clears dist/, *.egg-info, and any stray .so left in neug/
                  # (does NOT touch <repo>/build — keep that for incremental builds)

# Or from the repo root, also nuke <repo>/build:
make -C ../.. dist-clean
```

## Neug CLI

The `Neug` CLI tool provides an interactive shell for querying and managing NeuG database. It supports both local and remote database connections, Cypher query execution, and result formatting.

### Installation
`neug-cli` is included in neug package.

```bash
pip install neug
```

After installation, you can verify that `neug-cli` is installed correctly by running:

```bash
neug-cli --version
```

This should display:

```
neug-cli, version 0.1.3
```

### Usage

#### Overview

The `neug-cli` tool allows you to interact with the Neug database in both local and remote modes. To view the basic usage, run:

```bash
neug-cli --help
```

This displays:

```
Usage: neug-cli [OPTIONS] COMMAND [ARGS]...

  Neug CLI Tool.

Options:
  --version  Show the version and exit.
  --help     Show this message and exit.

Commands:
  connect  Connect to a remote database.
  open     Open a local database.
```

#### Start the Shell by Opening a Local Database

To open a local Neug database, specify the database path when starting the CLI. By default, the database is opened in read-write mode, and changes are persisted to disk when the shell exits. If the specified directory does not exist, it will be created automatically.

To open the database in read-only mode, use the `--readonly` or `-r` option.

```bash
neug-cli open <path-to-db> -m [read-only|read-write]
```

- `--mode`, `-m`: Specify mode of database.

#### Start the Shell by Connecting to a Remote Database

To connect to a remote Neug server, specify the server URI when starting the CLI. You can optionally provide a username, password, and query timeout. Note that remote connection support is under development.

```bash
neug-cli connect <host:port> [--timeout <seconds>]
```

- `--timeout`: Connection timeout in seconds (default: 300).

#### Interactive Shell Commands

Once you start the shell, you can execute Cypher queries and use various interactive commands:

- Enter Cypher queries directly to execute them.
- Use `:help` to display this help message.
- Use `:quit` or press Ctrl+C to leave the shell.
- Use `:max_rows <number>` to set the maximum number of rows to display for query results.
- Use `:ui <endpoint>` to start a web ui service.
- Multi-line commands are supported. Use ';' at the end to execute.
- Command history is supported; use the up/down arrow keys to navigate previous commands.

### Example

```bash
neug-cli open /tmp/modern_graph
```

This will open embedded Neug database at `/tmp/modern_graph` in `rw` mode by default, and start the shell. Then you can execute Cypher queries directly:

```
Welcome to the Neug shell. Type :help for usage hints.

neug > MATCH (n:person) RETURN n;
+-------------------------------------------------------+
| n                                                     |
+=======================================================+
| {_ID: 0, _LABEL: person, id: 1, name: marko, age: 29} |
+-------------------------------------------------------+
| {_ID: 1, _LABEL: person, id: 2, name: vadas, age: 27} |
+-------------------------------------------------------+
| {_ID: 2, _LABEL: person, id: 4, name: josh, age: 32}  |
+-------------------------------------------------------+
| {_ID: 3, _LABEL: person, id: 6, name: peter, age: 35} |
+-------------------------------------------------------+
```
