aevum-cli 0.2.0__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.
@@ -1,31 +1,31 @@
1
- # Python
2
- __pycache__/
3
- *.pyc
4
- *.pyo
5
- *.pyd
6
- .venv/
7
- *.egg-info/
8
-
9
- # Build
10
- dist/
11
- build/
12
-
13
- # Tools
14
- .mypy_cache/
15
- .ruff_cache/
16
- .pytest_cache/
17
- .hypothesis/
18
-
19
- # IDE
20
- .vscode/
21
- .idea/
22
- *.swp
23
- *.swo
24
-
25
- # OS
26
- .DS_Store
27
- Thumbs.db
28
-
29
- # Verify scripts (run locally, never commit)
30
- verify_phase*.py
31
- scripts/verify_phase*.py
1
+ # Python
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ .venv/
7
+ *.egg-info/
8
+
9
+ # Build
10
+ dist/
11
+ build/
12
+
13
+ # Tools
14
+ .mypy_cache/
15
+ .ruff_cache/
16
+ .pytest_cache/
17
+ .hypothesis/
18
+
19
+ # IDE
20
+ .vscode/
21
+ .idea/
22
+ *.swp
23
+ *.swo
24
+
25
+ # OS
26
+ .DS_Store
27
+ Thumbs.db
28
+
29
+ # Verify scripts (run locally, never commit)
30
+ verify_phase*.py
31
+ scripts/verify_phase*.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aevum-cli
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Aevum -- command-line interface for operating Aevum nodes.
5
5
  Project-URL: Homepage, https://aevum.build
6
6
  Project-URL: Repository, https://github.com/aevum-labs/aevum
@@ -1,12 +1,12 @@
1
- # aevum-cli
2
-
3
- Command-line interface for Aevum — start the server, manage store migrations, and inspect complication state.
4
-
5
- ```bash
6
- pip install aevum-cli
7
- aevum server start --graph memory
8
- aevum store migrate postgres:<dsn>
9
- aevum version
10
- ```
11
-
12
- See the [main repository README](https://github.com/aevum-labs/aevum) for full usage.
1
+ # aevum-cli
2
+
3
+ Command-line interface for Aevum — start the server, manage store migrations, and inspect complication state.
4
+
5
+ ```bash
6
+ pip install aevum-cli
7
+ aevum server start --graph memory
8
+ aevum store migrate postgres:<dsn>
9
+ aevum version
10
+ ```
11
+
12
+ See the [main repository README](https://github.com/aevum-labs/aevum) for full usage.
@@ -1,66 +1,66 @@
1
- [project]
2
- name = "aevum-cli"
3
- version = "0.2.0"
4
- description = "Aevum -- command-line interface for operating Aevum nodes."
5
- readme = "README.md"
6
- requires-python = ">=3.11"
7
- license = { text = "Apache-2.0" }
8
- classifiers = [
9
- "Development Status :: 3 - Alpha",
10
- "Intended Audience :: Developers",
11
- "License :: OSI Approved :: Apache Software License",
12
- "Programming Language :: Python :: 3.11",
13
- "Typing :: Typed",
14
- ]
15
- dependencies = [
16
- "aevum-core",
17
- "aevum-server",
18
- "typer[all]>=0.12",
19
- "uvicorn[standard]>=0.30",
20
- ]
21
-
22
- [project.scripts]
23
- aevum = "aevum.cli.__main__:app"
24
-
25
- [project.urls]
26
- Homepage = "https://aevum.build"
27
- Repository = "https://github.com/aevum-labs/aevum"
28
-
29
- [build-system]
30
- requires = ["hatchling"]
31
- build-backend = "hatchling.build"
32
-
33
- [tool.hatch.build.targets.wheel]
34
- packages = ["src/aevum"]
35
-
36
- [tool.uv.sources]
37
- aevum-core = { workspace = true }
38
- aevum-server = { workspace = true }
39
-
40
- [tool.pytest.ini_options]
41
- testpaths = ["tests"]
42
- asyncio_mode = "auto"
43
- addopts = "--tb=short"
44
- pythonpath = ["src", "tests"]
45
-
46
- [tool.mypy]
47
- strict = true
48
- python_version = "3.11"
49
- mypy_path = "src"
50
- explicit_package_bases = true
51
- ignore_missing_imports = true
52
-
53
- [tool.ruff]
54
- line-length = 130
55
-
56
- [tool.ruff.lint]
57
- select = ["E", "F", "UP", "B", "SIM", "I", "ANN"]
58
- ignore = ["ANN401"]
59
-
60
- [project.optional-dependencies]
61
- dev = [
62
- "pytest>=8.0",
63
- "pytest-asyncio>=0.23",
64
- "mypy>=1.10",
65
- "ruff>=0.9",
66
- ]
1
+ [project]
2
+ name = "aevum-cli"
3
+ version = "0.3.0"
4
+ description = "Aevum -- command-line interface for operating Aevum nodes."
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ license = { text = "Apache-2.0" }
8
+ classifiers = [
9
+ "Development Status :: 3 - Alpha",
10
+ "Intended Audience :: Developers",
11
+ "License :: OSI Approved :: Apache Software License",
12
+ "Programming Language :: Python :: 3.11",
13
+ "Typing :: Typed",
14
+ ]
15
+ dependencies = [
16
+ "aevum-core",
17
+ "aevum-server",
18
+ "typer[all]>=0.12",
19
+ "uvicorn[standard]>=0.30",
20
+ ]
21
+
22
+ [project.scripts]
23
+ aevum = "aevum.cli.__main__:app"
24
+
25
+ [project.urls]
26
+ Homepage = "https://aevum.build"
27
+ Repository = "https://github.com/aevum-labs/aevum"
28
+
29
+ [build-system]
30
+ requires = ["hatchling"]
31
+ build-backend = "hatchling.build"
32
+
33
+ [tool.hatch.build.targets.wheel]
34
+ packages = ["src/aevum"]
35
+
36
+ [tool.uv.sources]
37
+ aevum-core = { workspace = true }
38
+ aevum-server = { workspace = true }
39
+
40
+ [tool.pytest.ini_options]
41
+ testpaths = ["tests"]
42
+ asyncio_mode = "auto"
43
+ addopts = "--tb=short"
44
+ pythonpath = ["src", "tests"]
45
+
46
+ [tool.mypy]
47
+ strict = true
48
+ python_version = "3.11"
49
+ mypy_path = "src"
50
+ explicit_package_bases = true
51
+ ignore_missing_imports = true
52
+
53
+ [tool.ruff]
54
+ line-length = 130
55
+
56
+ [tool.ruff.lint]
57
+ select = ["E", "F", "UP", "B", "SIM", "I", "ANN"]
58
+ ignore = ["ANN401"]
59
+
60
+ [project.optional-dependencies]
61
+ dev = [
62
+ "pytest>=8.0",
63
+ "pytest-asyncio>=0.23",
64
+ "mypy>=1.10",
65
+ "ruff>=0.9",
66
+ ]
@@ -1,14 +1,14 @@
1
- """
2
- aevum.cli -- Command-line interface for operating Aevum nodes.
3
-
4
- Usage: aevum <command> [options]
5
-
6
- Commands:
7
- version Print installed package versions
8
- server start Start the HTTP API server
9
- store migrate Migrate between graph backends
10
- complication Manage installed complications
11
- conformance run Run the conformance suite
12
- """
13
-
14
- __version__ = "0.1.0"
1
+ """
2
+ aevum.cli -- Command-line interface for operating Aevum nodes.
3
+
4
+ Usage: aevum <command> [options]
5
+
6
+ Commands:
7
+ version Print installed package versions
8
+ server start Start the HTTP API server
9
+ store migrate Migrate between graph backends
10
+ complication Manage installed complications
11
+ conformance run Run the conformance suite
12
+ """
13
+
14
+ __version__ = "0.1.0"
@@ -1,9 +1,9 @@
1
- """
2
- Entry point: aevum <command>
3
- Invoked via [project.scripts] aevum = "aevum.cli.__main__:app"
4
- """
5
-
6
- from aevum.cli.app import app
7
-
8
- if __name__ == "__main__":
9
- app()
1
+ """
2
+ Entry point: aevum <command>
3
+ Invoked via [project.scripts] aevum = "aevum.cli.__main__:app"
4
+ """
5
+
6
+ from aevum.cli.app import app
7
+
8
+ if __name__ == "__main__":
9
+ app()
@@ -1,22 +1,22 @@
1
- """
2
- Top-level typer app. Sub-commands registered here.
3
- """
4
-
5
- from __future__ import annotations
6
-
7
- import typer
8
-
9
- from aevum.cli.commands import complication, conformance, server, store, version
10
-
11
- app = typer.Typer(
12
- name="aevum",
13
- help="Aevum context kernel -- command-line interface.",
14
- no_args_is_help=True,
15
- pretty_exceptions_enable=False,
16
- )
17
-
18
- app.add_typer(server.app, name="server")
19
- app.add_typer(store.app, name="store")
20
- app.add_typer(complication.app, name="complication")
21
- app.add_typer(conformance.app, name="conformance")
22
- app.command(name="version")(version.version_command)
1
+ """
2
+ Top-level typer app. Sub-commands registered here.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import typer
8
+
9
+ from aevum.cli.commands import complication, conformance, server, store, version
10
+
11
+ app = typer.Typer(
12
+ name="aevum",
13
+ help="Aevum context kernel -- command-line interface.",
14
+ no_args_is_help=True,
15
+ pretty_exceptions_enable=False,
16
+ )
17
+
18
+ app.add_typer(server.app, name="server")
19
+ app.add_typer(store.app, name="store")
20
+ app.add_typer(complication.app, name="complication")
21
+ app.add_typer(conformance.app, name="conformance")
22
+ app.command(name="version")(version.version_command)
@@ -1 +1 @@
1
- """aevum.cli.commands -- sub-command modules."""
1
+ """aevum.cli.commands -- sub-command modules."""
@@ -1,60 +1,60 @@
1
- """
2
- aevum complication list/suspend/resume -- manage complications.
3
- """
4
-
5
- from __future__ import annotations
6
-
7
- from typing import Annotated
8
-
9
- import typer
10
-
11
- app = typer.Typer(help="Manage installed complications.")
12
-
13
-
14
- @app.command("list")
15
- def list_complications(
16
- graph: Annotated[str, typer.Option(help="Graph backend")] = "memory",
17
- ) -> None:
18
- """List all installed complications with state and health."""
19
- from aevum.core.engine import Engine
20
- engine = Engine()
21
- complications = engine.list_complications()
22
- if not complications:
23
- typer.echo("No complications installed.")
24
- return
25
- typer.echo(f"Installed complications ({len(complications)}):")
26
- for name, entry in complications.items():
27
- state = entry["state"]
28
- typer.echo(f" {name}: {state}")
29
-
30
-
31
- @app.command("suspend")
32
- def suspend(
33
- name: Annotated[str, typer.Argument(help="Complication name to suspend")],
34
- ) -> None:
35
- """Suspend an ACTIVE complication."""
36
- from aevum.core.engine import Engine
37
- from aevum.core.exceptions import ComplicationError
38
- engine = Engine()
39
- try:
40
- engine.suspend_complication(name)
41
- typer.echo(f"Suspended: {name}")
42
- except ComplicationError as e:
43
- typer.echo(f"Error: {e}", err=True)
44
- raise typer.Exit(code=1) from e
45
-
46
-
47
- @app.command("resume")
48
- def resume(
49
- name: Annotated[str, typer.Argument(help="Complication name to resume")],
50
- ) -> None:
51
- """Resume a SUSPENDED complication."""
52
- from aevum.core.engine import Engine
53
- from aevum.core.exceptions import ComplicationError
54
- engine = Engine()
55
- try:
56
- engine.resume_complication(name)
57
- typer.echo(f"Resumed: {name}")
58
- except ComplicationError as e:
59
- typer.echo(f"Error: {e}", err=True)
60
- raise typer.Exit(code=1) from e
1
+ """
2
+ aevum complication list/suspend/resume -- manage complications.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import Annotated
8
+
9
+ import typer
10
+
11
+ app = typer.Typer(help="Manage installed complications.")
12
+
13
+
14
+ @app.command("list")
15
+ def list_complications(
16
+ graph: Annotated[str, typer.Option(help="Graph backend")] = "memory",
17
+ ) -> None:
18
+ """List all installed complications with state and health."""
19
+ from aevum.core.engine import Engine
20
+ engine = Engine()
21
+ complications = engine.list_complications()
22
+ if not complications:
23
+ typer.echo("No complications installed.")
24
+ return
25
+ typer.echo(f"Installed complications ({len(complications)}):")
26
+ for name, entry in complications.items():
27
+ state = entry["state"]
28
+ typer.echo(f" {name}: {state}")
29
+
30
+
31
+ @app.command("suspend")
32
+ def suspend(
33
+ name: Annotated[str, typer.Argument(help="Complication name to suspend")],
34
+ ) -> None:
35
+ """Suspend an ACTIVE complication."""
36
+ from aevum.core.engine import Engine
37
+ from aevum.core.exceptions import ComplicationError
38
+ engine = Engine()
39
+ try:
40
+ engine.suspend_complication(name)
41
+ typer.echo(f"Suspended: {name}")
42
+ except ComplicationError as e:
43
+ typer.echo(f"Error: {e}", err=True)
44
+ raise typer.Exit(code=1) from e
45
+
46
+
47
+ @app.command("resume")
48
+ def resume(
49
+ name: Annotated[str, typer.Argument(help="Complication name to resume")],
50
+ ) -> None:
51
+ """Resume a SUSPENDED complication."""
52
+ from aevum.core.engine import Engine
53
+ from aevum.core.exceptions import ComplicationError
54
+ engine = Engine()
55
+ try:
56
+ engine.resume_complication(name)
57
+ typer.echo(f"Resumed: {name}")
58
+ except ComplicationError as e:
59
+ typer.echo(f"Error: {e}", err=True)
60
+ raise typer.Exit(code=1) from e
@@ -1,46 +1,46 @@
1
- """
2
- aevum conformance run -- run the conformance suite.
3
- """
4
-
5
- from __future__ import annotations
6
-
7
- import subprocess
8
- from typing import Annotated
9
-
10
- import typer
11
-
12
- app = typer.Typer(help="Run the Aevum conformance suite.")
13
-
14
-
15
- @app.command("run")
16
- def run(
17
- impl: Annotated[
18
- str,
19
- typer.Option(help="Python import path to AevumProtocol implementation"),
20
- ] = "aevum.core.engine:Engine",
21
- verbose: Annotated[bool, typer.Option("--verbose", "-v")] = False,
22
- ) -> None:
23
- """
24
- Run the aevum-conformance suite against an implementation.
25
-
26
- Requires aevum-conformance to be installed separately:
27
- pip install aevum-conformance
28
- """
29
- try:
30
- import importlib
31
- importlib.import_module("conformance")
32
- except ImportError:
33
- typer.echo(
34
- "aevum-conformance is not installed. "
35
- "Install from: github.com/aevum-labs/aevum-conformance",
36
- err=True,
37
- )
38
- raise typer.Exit(code=1) from None
39
-
40
- args = ["python", "-m", "pytest", "conformance/"]
41
- if verbose:
42
- args.append("-v")
43
-
44
- typer.echo(f"Running conformance suite against: {impl}")
45
- result = subprocess.run(args)
46
- raise typer.Exit(code=result.returncode)
1
+ """
2
+ aevum conformance run -- run the conformance suite.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import subprocess
8
+ from typing import Annotated
9
+
10
+ import typer
11
+
12
+ app = typer.Typer(help="Run the Aevum conformance suite.")
13
+
14
+
15
+ @app.command("run")
16
+ def run(
17
+ impl: Annotated[
18
+ str,
19
+ typer.Option(help="Python import path to AevumProtocol implementation"),
20
+ ] = "aevum.core.engine:Engine",
21
+ verbose: Annotated[bool, typer.Option("--verbose", "-v")] = False,
22
+ ) -> None:
23
+ """
24
+ Run the aevum-conformance suite against an implementation.
25
+
26
+ Requires aevum-conformance to be installed separately:
27
+ pip install aevum-conformance
28
+ """
29
+ try:
30
+ import importlib
31
+ importlib.import_module("conformance")
32
+ except ImportError:
33
+ typer.echo(
34
+ "aevum-conformance is not installed. "
35
+ "Install from: github.com/aevum-labs/aevum-conformance",
36
+ err=True,
37
+ )
38
+ raise typer.Exit(code=1) from None
39
+
40
+ args = ["python", "-m", "pytest", "conformance/"]
41
+ if verbose:
42
+ args.append("-v")
43
+
44
+ typer.echo(f"Running conformance suite against: {impl}")
45
+ result = subprocess.run(args)
46
+ raise typer.Exit(code=result.returncode)
@@ -1,92 +1,92 @@
1
- """
2
- aevum server start -- start the Aevum HTTP API server.
3
- """
4
-
5
- from __future__ import annotations
6
-
7
- from typing import TYPE_CHECKING, Annotated
8
-
9
- import typer
10
- import uvicorn
11
-
12
- if TYPE_CHECKING:
13
- from aevum.core.engine import Engine
14
-
15
- app = typer.Typer(help="Manage the Aevum HTTP API server.")
16
-
17
-
18
- @app.command("start")
19
- def start(
20
- host: Annotated[str, typer.Option(help="Bind host")] = "0.0.0.0",
21
- port: Annotated[int, typer.Option(help="Bind port")] = 8000,
22
- workers: Annotated[int, typer.Option(help="Number of uvicorn workers")] = 1,
23
- graph: Annotated[
24
- str,
25
- typer.Option(
26
- help="Graph backend. Options: memory | oxigraph:<path> | postgres:<dsn>"
27
- ),
28
- ] = "memory",
29
- api_key: Annotated[
30
- str | None,
31
- typer.Option(envvar="AEVUM_API_KEY", help="API key (overrides AEVUM_API_KEY env var)"),
32
- ] = None,
33
- reload: Annotated[bool, typer.Option(help="Enable auto-reload (dev only)")] = False,
34
- ) -> None:
35
- """Start the Aevum HTTP API server."""
36
- import os
37
-
38
- if api_key:
39
- os.environ["AEVUM_API_KEY"] = api_key
40
-
41
- engine = _build_engine(graph)
42
-
43
- from aevum.server.app import create_app
44
- from aevum.server.core.config import Settings
45
-
46
- settings_with_overrides = Settings(
47
- host=host,
48
- port=port,
49
- )
50
- app_instance = create_app(engine=engine, settings=settings_with_overrides)
51
-
52
- typer.echo(f"Starting Aevum server on {host}:{port} (graph={graph})")
53
- uvicorn.run(
54
- app_instance,
55
- host=host,
56
- port=port,
57
- workers=workers if not reload else 1,
58
- reload=reload,
59
- )
60
-
61
-
62
- def _build_engine(graph: str) -> Engine:
63
- """Build an Engine from the --graph flag."""
64
- from aevum.core.engine import Engine
65
-
66
- if graph == "memory":
67
- typer.echo("Graph backend: in-memory (dev only -- data lost on restart)")
68
- return Engine()
69
-
70
- if graph.startswith("oxigraph:"):
71
- path = graph[len("oxigraph:"):]
72
- from aevum.store.oxigraph import OxigraphStore
73
- typer.echo(f"Graph backend: Oxigraph at {path}")
74
- return Engine(graph_store=OxigraphStore(path=path))
75
-
76
- if graph.startswith("postgres:"):
77
- dsn = graph[len("postgres:"):]
78
- try:
79
- import psycopg
80
- from aevum.store.postgres import PostgresStore
81
- from aevum.store.postgres.store import initialize_schema
82
- conn = psycopg.connect(dsn)
83
- initialize_schema(conn)
84
- typer.echo("Graph backend: PostgreSQL")
85
- return Engine(graph_store=PostgresStore(conn))
86
- except ImportError:
87
- typer.echo("Error: aevum-store-postgres is not installed.", err=True)
88
- raise typer.Exit(code=1) from None
89
-
90
- typer.echo(f"Unknown graph backend: {graph!r}", err=True)
91
- typer.echo("Options: memory | oxigraph:<path> | postgres:<dsn>", err=True)
92
- raise typer.Exit(code=1)
1
+ """
2
+ aevum server start -- start the Aevum HTTP API server.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import TYPE_CHECKING, Annotated
8
+
9
+ import typer
10
+ import uvicorn
11
+
12
+ if TYPE_CHECKING:
13
+ from aevum.core.engine import Engine
14
+
15
+ app = typer.Typer(help="Manage the Aevum HTTP API server.")
16
+
17
+
18
+ @app.command("start")
19
+ def start(
20
+ host: Annotated[str, typer.Option(help="Bind host")] = "0.0.0.0",
21
+ port: Annotated[int, typer.Option(help="Bind port")] = 8000,
22
+ workers: Annotated[int, typer.Option(help="Number of uvicorn workers")] = 1,
23
+ graph: Annotated[
24
+ str,
25
+ typer.Option(
26
+ help="Graph backend. Options: memory | oxigraph:<path> | postgres:<dsn>"
27
+ ),
28
+ ] = "memory",
29
+ api_key: Annotated[
30
+ str | None,
31
+ typer.Option(envvar="AEVUM_API_KEY", help="API key (overrides AEVUM_API_KEY env var)"),
32
+ ] = None,
33
+ reload: Annotated[bool, typer.Option(help="Enable auto-reload (dev only)")] = False,
34
+ ) -> None:
35
+ """Start the Aevum HTTP API server."""
36
+ import os
37
+
38
+ if api_key:
39
+ os.environ["AEVUM_API_KEY"] = api_key
40
+
41
+ engine = _build_engine(graph)
42
+
43
+ from aevum.server.app import create_app
44
+ from aevum.server.core.config import Settings
45
+
46
+ settings_with_overrides = Settings(
47
+ host=host,
48
+ port=port,
49
+ )
50
+ app_instance = create_app(engine=engine, settings=settings_with_overrides)
51
+
52
+ typer.echo(f"Starting Aevum server on {host}:{port} (graph={graph})")
53
+ uvicorn.run(
54
+ app_instance,
55
+ host=host,
56
+ port=port,
57
+ workers=workers if not reload else 1,
58
+ reload=reload,
59
+ )
60
+
61
+
62
+ def _build_engine(graph: str) -> Engine:
63
+ """Build an Engine from the --graph flag."""
64
+ from aevum.core.engine import Engine
65
+
66
+ if graph == "memory":
67
+ typer.echo("Graph backend: in-memory (dev only -- data lost on restart)")
68
+ return Engine()
69
+
70
+ if graph.startswith("oxigraph:"):
71
+ path = graph[len("oxigraph:"):]
72
+ from aevum.store.oxigraph import OxigraphStore
73
+ typer.echo(f"Graph backend: Oxigraph at {path}")
74
+ return Engine(graph_store=OxigraphStore(path=path))
75
+
76
+ if graph.startswith("postgres:"):
77
+ dsn = graph[len("postgres:"):]
78
+ try:
79
+ import psycopg
80
+ from aevum.store.postgres import PostgresStore
81
+ from aevum.store.postgres.store import initialize_schema
82
+ conn = psycopg.connect(dsn)
83
+ initialize_schema(conn)
84
+ typer.echo("Graph backend: PostgreSQL")
85
+ return Engine(graph_store=PostgresStore(conn))
86
+ except ImportError:
87
+ typer.echo("Error: aevum-store-postgres is not installed.", err=True)
88
+ raise typer.Exit(code=1) from None
89
+
90
+ typer.echo(f"Unknown graph backend: {graph!r}", err=True)
91
+ typer.echo("Options: memory | oxigraph:<path> | postgres:<dsn>", err=True)
92
+ raise typer.Exit(code=1)
@@ -1,51 +1,51 @@
1
- """
2
- aevum store migrate -- migrate between graph backends.
3
- """
4
-
5
- from __future__ import annotations
6
-
7
- from typing import Annotated
8
-
9
- import typer
10
-
11
- app = typer.Typer(help="Manage graph store backends.")
12
-
13
-
14
- @app.command("migrate")
15
- def migrate(
16
- from_backend: Annotated[str, typer.Option("--from", help="Source backend (oxigraph:<path>)")] = "",
17
- to_backend: Annotated[str, typer.Option("--to", help="Target backend (postgres:<dsn>)")] = "",
18
- ) -> None:
19
- """Migrate graph data between backends."""
20
- if not from_backend or not to_backend:
21
- typer.echo("Both --from and --to are required.", err=True)
22
- raise typer.Exit(code=1)
23
-
24
- if not from_backend.startswith("oxigraph:"):
25
- typer.echo(f"Unsupported source backend: {from_backend!r}", err=True)
26
- typer.echo("Currently supported source: oxigraph:<path>", err=True)
27
- raise typer.Exit(code=1)
28
-
29
- if not to_backend.startswith("postgres:"):
30
- typer.echo(f"Unsupported target backend: {to_backend!r}", err=True)
31
- typer.echo("Currently supported target: postgres:<dsn>", err=True)
32
- raise typer.Exit(code=1)
33
-
34
- try:
35
- from aevum.store.postgres.store import migrate_from_oxigraph
36
- except ImportError:
37
- typer.echo("Error: aevum-store-postgres is not installed.", err=True)
38
- raise typer.Exit(code=1) from None
39
-
40
- oxigraph_path = from_backend[len("oxigraph:"):]
41
- postgres_dsn = to_backend[len("postgres:"):]
42
-
43
- typer.echo(f"Migrating: {oxigraph_path} -> PostgreSQL")
44
- try:
45
- import psycopg
46
- conn = psycopg.connect(postgres_dsn)
47
- migrated = migrate_from_oxigraph(oxigraph_path, conn)
48
- typer.echo(f"Migration complete: {migrated} entities transferred.")
49
- except Exception as e:
50
- typer.echo(f"Migration failed: {e}", err=True)
51
- raise typer.Exit(code=1) from e
1
+ """
2
+ aevum store migrate -- migrate between graph backends.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import Annotated
8
+
9
+ import typer
10
+
11
+ app = typer.Typer(help="Manage graph store backends.")
12
+
13
+
14
+ @app.command("migrate")
15
+ def migrate(
16
+ from_backend: Annotated[str, typer.Option("--from", help="Source backend (oxigraph:<path>)")] = "",
17
+ to_backend: Annotated[str, typer.Option("--to", help="Target backend (postgres:<dsn>)")] = "",
18
+ ) -> None:
19
+ """Migrate graph data between backends."""
20
+ if not from_backend or not to_backend:
21
+ typer.echo("Both --from and --to are required.", err=True)
22
+ raise typer.Exit(code=1)
23
+
24
+ if not from_backend.startswith("oxigraph:"):
25
+ typer.echo(f"Unsupported source backend: {from_backend!r}", err=True)
26
+ typer.echo("Currently supported source: oxigraph:<path>", err=True)
27
+ raise typer.Exit(code=1)
28
+
29
+ if not to_backend.startswith("postgres:"):
30
+ typer.echo(f"Unsupported target backend: {to_backend!r}", err=True)
31
+ typer.echo("Currently supported target: postgres:<dsn>", err=True)
32
+ raise typer.Exit(code=1)
33
+
34
+ try:
35
+ from aevum.store.postgres.store import migrate_from_oxigraph
36
+ except ImportError:
37
+ typer.echo("Error: aevum-store-postgres is not installed.", err=True)
38
+ raise typer.Exit(code=1) from None
39
+
40
+ oxigraph_path = from_backend[len("oxigraph:"):]
41
+ postgres_dsn = to_backend[len("postgres:"):]
42
+
43
+ typer.echo(f"Migrating: {oxigraph_path} -> PostgreSQL")
44
+ try:
45
+ import psycopg
46
+ conn = psycopg.connect(postgres_dsn)
47
+ migrated = migrate_from_oxigraph(oxigraph_path, conn)
48
+ typer.echo(f"Migration complete: {migrated} entities transferred.")
49
+ except Exception as e:
50
+ typer.echo(f"Migration failed: {e}", err=True)
51
+ raise typer.Exit(code=1) from e
@@ -1,32 +1,32 @@
1
- """
2
- aevum version -- print installed package versions.
3
- """
4
-
5
- from __future__ import annotations
6
-
7
- from importlib.metadata import PackageNotFoundError, version
8
-
9
- import typer
10
-
11
- _PACKAGES = [
12
- "aevum-core",
13
- "aevum-server",
14
- "aevum-sdk",
15
- "aevum-store-oxigraph",
16
- "aevum-store-postgres",
17
- "aevum-mcp",
18
- "aevum-oidc",
19
- "aevum-llm",
20
- "aevum-cli",
21
- ]
22
-
23
-
24
- def version_command() -> None:
25
- """Print versions of all installed Aevum packages."""
26
- typer.echo("Aevum package versions:")
27
- for pkg in _PACKAGES:
28
- try:
29
- ver = version(pkg)
30
- typer.echo(f" {pkg}: {ver}")
31
- except PackageNotFoundError:
32
- typer.echo(f" {pkg}: not installed")
1
+ """
2
+ aevum version -- print installed package versions.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from importlib.metadata import PackageNotFoundError, version
8
+
9
+ import typer
10
+
11
+ _PACKAGES = [
12
+ "aevum-core",
13
+ "aevum-server",
14
+ "aevum-sdk",
15
+ "aevum-store-oxigraph",
16
+ "aevum-store-postgres",
17
+ "aevum-mcp",
18
+ "aevum-oidc",
19
+ "aevum-llm",
20
+ "aevum-cli",
21
+ ]
22
+
23
+
24
+ def version_command() -> None:
25
+ """Print versions of all installed Aevum packages."""
26
+ typer.echo("Aevum package versions:")
27
+ for pkg in _PACKAGES:
28
+ try:
29
+ ver = version(pkg)
30
+ typer.echo(f" {pkg}: {ver}")
31
+ except PackageNotFoundError:
32
+ typer.echo(f" {pkg}: not installed")
@@ -1,99 +1,99 @@
1
- """
2
- Tests for aevum-cli commands.
3
- Uses typer's CliRunner -- no real server, no real graph backend.
4
-
5
- NO tests/__init__.py (standing rule).
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- import re
11
-
12
- from typer.testing import CliRunner
13
-
14
- from aevum.cli.app import app
15
-
16
- runner = CliRunner()
17
-
18
- _ANSI = re.compile(r"\x1b\[[0-9;]*[mGKH]")
19
-
20
-
21
- def plain(text: str) -> str:
22
- """Strip ANSI escape codes so assertions work regardless of FORCE_COLOR."""
23
- return _ANSI.sub("", text)
24
-
25
-
26
- def test_version_command() -> None:
27
- result = runner.invoke(app, ["version"])
28
- assert result.exit_code == 0
29
- assert "aevum-core" in plain(result.output)
30
- assert "aevum-cli" in plain(result.output)
31
-
32
-
33
- def test_version_shows_not_installed_for_missing() -> None:
34
- result = runner.invoke(app, ["version"])
35
- assert "not installed" in plain(result.output) or result.exit_code == 0
36
-
37
-
38
- def test_server_start_help() -> None:
39
- result = runner.invoke(app, ["server", "start", "--help"])
40
- assert result.exit_code == 0
41
- out = plain(result.output)
42
- assert "--host" in out
43
- assert "--port" in out
44
- assert "--graph" in out
45
- assert "--workers" in out
46
-
47
-
48
- def test_store_migrate_help() -> None:
49
- result = runner.invoke(app, ["store", "migrate", "--help"])
50
- assert result.exit_code == 0
51
- out = plain(result.output)
52
- assert "--from" in out
53
- assert "--to" in out
54
-
55
-
56
- def test_complication_list_empty() -> None:
57
- result = runner.invoke(app, ["complication", "list"])
58
- assert result.exit_code == 0
59
- assert "No complications installed" in plain(result.output)
60
-
61
-
62
- def test_complication_list_help() -> None:
63
- result = runner.invoke(app, ["complication", "list", "--help"])
64
- assert result.exit_code == 0
65
-
66
-
67
- def test_complication_suspend_help() -> None:
68
- result = runner.invoke(app, ["complication", "suspend", "--help"])
69
- assert result.exit_code == 0
70
-
71
-
72
- def test_complication_resume_help() -> None:
73
- result = runner.invoke(app, ["complication", "resume", "--help"])
74
- assert result.exit_code == 0
75
-
76
-
77
- def test_conformance_run_help() -> None:
78
- result = runner.invoke(app, ["conformance", "run", "--help"])
79
- assert result.exit_code == 0
80
- assert "--impl" in plain(result.output)
81
-
82
-
83
- def test_store_migrate_requires_both_flags() -> None:
84
- result = runner.invoke(app, ["store", "migrate"])
85
- assert result.exit_code != 0
86
-
87
-
88
- def test_store_migrate_unsupported_source() -> None:
89
- result = runner.invoke(app, ["store", "migrate", "--from", "memory:", "--to", "postgres:dsn"])
90
- assert result.exit_code != 0
91
- assert "Unsupported source" in plain(result.output)
92
-
93
-
94
- def test_top_level_help() -> None:
95
- result = runner.invoke(app, ["--help"])
96
- assert result.exit_code == 0
97
- out = plain(result.output)
98
- for cmd in ["version", "server", "store", "complication", "conformance"]:
99
- assert cmd in out
1
+ """
2
+ Tests for aevum-cli commands.
3
+ Uses typer's CliRunner -- no real server, no real graph backend.
4
+
5
+ NO tests/__init__.py (standing rule).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import re
11
+
12
+ from typer.testing import CliRunner
13
+
14
+ from aevum.cli.app import app
15
+
16
+ runner = CliRunner()
17
+
18
+ _ANSI = re.compile(r"\x1b\[[0-9;]*[mGKH]")
19
+
20
+
21
+ def plain(text: str) -> str:
22
+ """Strip ANSI escape codes so assertions work regardless of FORCE_COLOR."""
23
+ return _ANSI.sub("", text)
24
+
25
+
26
+ def test_version_command() -> None:
27
+ result = runner.invoke(app, ["version"])
28
+ assert result.exit_code == 0
29
+ assert "aevum-core" in plain(result.output)
30
+ assert "aevum-cli" in plain(result.output)
31
+
32
+
33
+ def test_version_shows_not_installed_for_missing() -> None:
34
+ result = runner.invoke(app, ["version"])
35
+ assert "not installed" in plain(result.output) or result.exit_code == 0
36
+
37
+
38
+ def test_server_start_help() -> None:
39
+ result = runner.invoke(app, ["server", "start", "--help"])
40
+ assert result.exit_code == 0
41
+ out = plain(result.output)
42
+ assert "--host" in out
43
+ assert "--port" in out
44
+ assert "--graph" in out
45
+ assert "--workers" in out
46
+
47
+
48
+ def test_store_migrate_help() -> None:
49
+ result = runner.invoke(app, ["store", "migrate", "--help"])
50
+ assert result.exit_code == 0
51
+ out = plain(result.output)
52
+ assert "--from" in out
53
+ assert "--to" in out
54
+
55
+
56
+ def test_complication_list_empty() -> None:
57
+ result = runner.invoke(app, ["complication", "list"])
58
+ assert result.exit_code == 0
59
+ assert "No complications installed" in plain(result.output)
60
+
61
+
62
+ def test_complication_list_help() -> None:
63
+ result = runner.invoke(app, ["complication", "list", "--help"])
64
+ assert result.exit_code == 0
65
+
66
+
67
+ def test_complication_suspend_help() -> None:
68
+ result = runner.invoke(app, ["complication", "suspend", "--help"])
69
+ assert result.exit_code == 0
70
+
71
+
72
+ def test_complication_resume_help() -> None:
73
+ result = runner.invoke(app, ["complication", "resume", "--help"])
74
+ assert result.exit_code == 0
75
+
76
+
77
+ def test_conformance_run_help() -> None:
78
+ result = runner.invoke(app, ["conformance", "run", "--help"])
79
+ assert result.exit_code == 0
80
+ assert "--impl" in plain(result.output)
81
+
82
+
83
+ def test_store_migrate_requires_both_flags() -> None:
84
+ result = runner.invoke(app, ["store", "migrate"])
85
+ assert result.exit_code != 0
86
+
87
+
88
+ def test_store_migrate_unsupported_source() -> None:
89
+ result = runner.invoke(app, ["store", "migrate", "--from", "memory:", "--to", "postgres:dsn"])
90
+ assert result.exit_code != 0
91
+ assert "Unsupported source" in plain(result.output)
92
+
93
+
94
+ def test_top_level_help() -> None:
95
+ result = runner.invoke(app, ["--help"])
96
+ assert result.exit_code == 0
97
+ out = plain(result.output)
98
+ for cmd in ["version", "server", "store", "complication", "conformance"]:
99
+ assert cmd in out