Skip to content

Commit e80d564

Browse files
gatesndanking
authored andcommitted
Ship Vortex CLI as part of Python package (#6233)
After installing the python package, the CLI can be run as `vx`. Fixes #2589 --------- Signed-off-by: Nicholas Gates <nick@nickgates.com>
1 parent e0b6ec8 commit e80d564

File tree

9 files changed

+73
-2
lines changed

9 files changed

+73
-2
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ vortex-cuda-macros = { path = "./vortex-cuda/macros" }
285285
vortex-duckdb = { path = "./vortex-duckdb", default-features = false }
286286
vortex-test-e2e = { path = "./vortex-test/e2e", default-features = false }
287287
vortex-test-e2e-cuda = { path = "./vortex-test/e2e-cuda", default-features = false }
288+
vortex-tui = { path = "./vortex-tui" }
288289

289290
[workspace.dependencies.getrandom_v03]
290291
features = ["wasm_js"]

vortex-python/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ tokio = { workspace = true, features = ["fs", "rt-multi-thread"] }
5252
tracing = { workspace = true, features = ["std", "log"] }
5353
url = { workspace = true }
5454
vortex = { workspace = true, features = ["object_store", "tokio"] }
55+
vortex-tui = { workspace = true }
5556

5657
[dev-dependencies]
5758
vortex-array = { workspace = true, features = ["_test-harness"] }

vortex-python/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ classifiers = [
3333
"Topic :: Scientific/Engineering",
3434
]
3535

36+
[project.scripts]
37+
vx = "vortex.cli:main"
38+
3639
[project.optional-dependencies]
3740
polars = ["polars>=1.31.0"]
3841
pandas = ["pandas>=2.2.0"]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
def launch(args: list[str]) -> None: ...

vortex-python/python/vortex/cli.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
import sys
5+
6+
7+
def main() -> None:
8+
from vortex._lib.cli import launch # pyright: ignore[reportMissingModuleSource]
9+
10+
launch(sys.argv)

vortex-python/src/cli.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
use pyo3::exceptions::PyRuntimeError;
5+
use pyo3::prelude::*;
6+
7+
use crate::SESSION;
8+
use crate::TOKIO_RUNTIME;
9+
use crate::install_module;
10+
11+
pub(crate) fn init(py: Python, parent: &Bound<PyModule>) -> PyResult<()> {
12+
let m = PyModule::new(py, "cli")?;
13+
parent.add_submodule(&m)?;
14+
install_module("vortex._lib.cli", &m)?;
15+
16+
m.add_function(wrap_pyfunction!(launch, &m)?)?;
17+
18+
Ok(())
19+
}
20+
21+
/// Launch the `vx` CLI with the given arguments.
22+
///
23+
/// Parameters
24+
/// ----------
25+
/// args : list[str]
26+
/// Command-line arguments, typically ``sys.argv``.
27+
#[pyfunction]
28+
fn launch(py: Python, args: Vec<String>) -> PyResult<()> {
29+
py.detach(|| TOKIO_RUNTIME.block_on(vortex_tui::launch_from(&SESSION, args)))
30+
.map_err(|e| PyRuntimeError::new_err(e.to_string()))
31+
}

vortex-python/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use pyo3::prelude::*;
99

1010
pub(crate) mod arrays;
1111
pub mod arrow;
12+
mod cli;
1213
mod compress;
1314
mod dataset;
1415
pub(crate) mod dtype;
@@ -61,6 +62,7 @@ fn _lib(py: Python, m: &Bound<PyModule>) -> PyResult<()> {
6162

6263
// Initialize our submodules, living under vortex._lib
6364
arrays::init(py, m)?;
65+
cli::init(py, m)?;
6466
compress::init(py, m)?;
6567
dataset::init(py, m)?;
6668
dtype::init(py, m)?;

vortex-tui/src/lib.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#![deny(clippy::missing_safety_doc)]
2323
#![deny(missing_docs)]
2424

25+
use std::ffi::OsString;
2526
use std::path::PathBuf;
2627

2728
use clap::CommandFactory;
@@ -79,13 +80,30 @@ impl Commands {
7980

8081
/// Main entrypoint for `vx` that launches a [`VortexSession`].
8182
///
83+
/// Parses arguments from [`std::env::args_os`]. See [`launch_from`] to supply explicit arguments.
84+
///
8285
/// # Errors
8386
///
8487
/// Raises any errors from subcommands.
8588
pub async fn launch(session: &VortexSession) -> anyhow::Result<()> {
86-
env_logger::init();
89+
launch_from(session, std::env::args_os()).await
90+
}
91+
92+
/// Launch `vx` with explicit command-line arguments.
93+
///
94+
/// This is useful when embedding the TUI inside another process (e.g. Python) where
95+
/// [`std::env::args`] may not reflect the intended arguments.
96+
///
97+
/// # Errors
98+
///
99+
/// Raises any errors from subcommands.
100+
pub async fn launch_from(
101+
session: &VortexSession,
102+
args: impl IntoIterator<Item = impl Into<OsString> + Clone>,
103+
) -> anyhow::Result<()> {
104+
let _ = env_logger::try_init();
87105

88-
let cli = Cli::parse();
106+
let cli = Cli::parse_from(args);
89107

90108
let path = cli.command.file_path();
91109
if !std::fs::exists(path)? {

0 commit comments

Comments
 (0)