From 87ecaec3f3a392aefb27f25fb1adbe112dd13ef2 Mon Sep 17 00:00:00 2001 From: Matteo Rosati Date: Sun, 10 May 2026 16:56:50 +0200 Subject: [PATCH] add command aliases --- chromy/cli.py | 34 ++++++++++---- tests/test_cli.py | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 8 deletions(-) diff --git a/chromy/cli.py b/chromy/cli.py index aa090b7..e30d76d 100644 --- a/chromy/cli.py +++ b/chromy/cli.py @@ -24,7 +24,15 @@ app = typer.Typer( "Storage location:\n" "- By default, Chromy uses Chroma's default persistent location behavior.\n" f"- Set {CHROMA_FOLDER_ENV_VAR} to a parent directory to override it.\n" - f"- Chromy stores data in <{CHROMA_FOLDER_ENV_VAR}>/chroma." + f"- Chromy stores data in <{CHROMA_FOLDER_ENV_VAR}>/chroma.\n\n" + "Command aliases:\n" + "- list-collections: lc\n" + "- create-collection: cc\n" + "- delete-collection: dc\n" + "- count: c\n" + "- import: i\n" + "- query: q\n" + "- delete: del" ), invoke_without_command=True, ) @@ -59,9 +67,10 @@ def main(ctx: typer.Context) -> None: # ------------------------------------------------------------------------------ # LIST COLLECTIONS # ------------------------------------------------------------------------------ +@app.command("lc", help="Alias for list-collections.") @app.command( "list-collections", - help="List all collections stored in the local Chroma database.", + help="List all collections stored in the local Chroma database. Alias: lc.", ) def list_collections() -> None: _run(handle_list_collections) @@ -70,9 +79,10 @@ def list_collections() -> None: # ------------------------------------------------------------------------------ # CREATE A COLLECTION # ------------------------------------------------------------------------------ +@app.command("cc", help="Alias for create-collection.") @app.command( "create-collection", - help="Create a collection in the local Chroma database.", + help="Create a collection in the local Chroma database. Alias: cc.", ) def create_collection( collection: Annotated[ @@ -89,9 +99,10 @@ def create_collection( # ------------------------------------------------------------------------------ # DELETE A COLLECTION # ------------------------------------------------------------------------------ +@app.command("dc", help="Alias for delete-collection.") @app.command( "delete-collection", - help="Delete a collection from the local Chroma database.", + help="Delete a collection from the local Chroma database. Alias: dc.", ) def delete_collection( collection: Annotated[ @@ -108,9 +119,10 @@ def delete_collection( # ------------------------------------------------------------------------------ # COUNT RECORDS # ------------------------------------------------------------------------------ +@app.command("c", help="Alias for count.") @app.command( "count", - help="Count records in a collection from the local Chroma database.", + help="Count records in a collection from the local Chroma database. Alias: c.", ) def count( collection: Annotated[ @@ -127,11 +139,12 @@ def count( # ------------------------------------------------------------------------------ # IMPORT DATA # ------------------------------------------------------------------------------ +@app.command("i", help="Alias for import.") @app.command( "import", help=( "Chunk, embed, and add one or more files to a collection in the " - "local Chroma database." + "local Chroma database. Alias: i." ), ) def import_data( @@ -155,7 +168,8 @@ def import_data( # ------------------------------------------------------------------------------ # QUERY # ------------------------------------------------------------------------------ -@app.command("query", help="Query a collection with the provided text.") +@app.command("q", help="Alias for query.") +@app.command("query", help="Query a collection with the provided text. Alias: q.") def query( collection: Annotated[ str, @@ -175,7 +189,11 @@ def query( # ------------------------------------------------------------------------------ # DELETE DATA # ------------------------------------------------------------------------------ -@app.command("delete", help="Delete records from a collection using a metadata filter.") +@app.command("del", help="Alias for delete.") +@app.command( + "delete", + help="Delete records from a collection using a metadata filter. Alias: del.", +) def delete_records( collection: Annotated[ str, diff --git a/tests/test_cli.py b/tests/test_cli.py index 668a611..53f9b71 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -95,6 +95,106 @@ class CliTests(unittest.TestCase): "The 'notes' collection contains 7 records.\n", ) + def test_command_aliases(self) -> None: + with self.subTest(alias="lc"): + with patch( + "chromy.handlers.list_collections.list_collections", + return_value=[], + ) as mocked: + result = _invoke(["lc"]) + + mocked.assert_called_once_with() + self.assertEqual(result.exit_code, 0) + self.assertEqual(result.stdout, "No collections found.\n") + + with self.subTest(alias="cc"): + with patch( + "chromy.handlers.create_collection.create_collection", + return_value="notes", + ) as mocked: + result = _invoke(["cc", "notes"]) + + mocked.assert_called_once_with("notes") + self.assertEqual(result.exit_code, 0) + self.assertEqual(result.stdout, "Created: collection 'notes'.\n") + + with self.subTest(alias="dc"): + with patch( + "chromy.handlers.delete_collection.delete_collection", + ) as mocked: + result = _invoke(["dc", "notes"]) + + mocked.assert_called_once_with("notes") + self.assertEqual(result.exit_code, 0) + self.assertEqual(result.stdout, "Deleted collection 'notes'.\n") + + with self.subTest(alias="c"): + with patch( + "chromy.handlers.count_collection.count_collection", + return_value=7, + ) as mocked: + result = _invoke(["c", "notes"]) + + mocked.assert_called_once_with("notes") + self.assertEqual(result.exit_code, 0) + self.assertEqual( + result.stdout, + "The 'notes' collection contains 7 records.\n", + ) + + with self.subTest(alias="i"): + with patch( + "chromy.handlers.import_data.ingest_file", + return_value=3, + ) as mocked: + result = _invoke(["i", "notes", "romeo_and_juliet.txt"]) + + mocked.assert_called_once_with( + "notes", + self._fixture_path("romeo_and_juliet.txt"), + ) + self.assertEqual(result.exit_code, 0) + self.assertEqual( + result.stdout, + "Added 3 records from 'romeo_and_juliet.txt' to collection 'notes'.\n" + "Imported 1 file(s) successfully; 0 failed.\n", + ) + + with self.subTest(alias="q"): + query_result = {"ids": [["1"]], "documents": [["hello"]]} + with ( + patch( + "chromy.handlers.query.run_query", + return_value=query_result, + ) as mocked, + patch( + "chromy.handlers.query.format_query_result", + return_value=["1"], + ), + ): + result = _invoke(["q", "notes", "Where is Romeo?"]) + + mocked.assert_called_once_with("notes", "Where is Romeo?") + self.assertEqual(result.exit_code, 0) + self.assertEqual(result.stdout, "1\n") + + with self.subTest(alias="del"): + with patch( + "chromy.handlers.delete_collection.delete_data", + return_value=2, + ) as mocked: + result = _invoke( + ["del", "notes", "--where", "file_name=play.txt"], + ) + + mocked.assert_called_once_with("notes", {"file_name": "play.txt"}) + self.assertEqual(result.exit_code, 0) + self.assertEqual( + result.stdout, + "Deleted 2 record(s) from collection 'notes' where " + "file_name=play.txt.\n", + ) + def test_import_data(self) -> None: with patch( "chromy.handlers.import_data.ingest_file", @@ -268,6 +368,19 @@ class CliTests(unittest.TestCase): self.assertIn("parent directory", result.stdout) self.assertIn("/chroma", result.stdout) + def test_cli_help_documents_command_aliases(self) -> None: + result = _invoke(["--help"]) + + self.assertEqual(result.exit_code, 0) + self.assertIn("Command aliases", result.stdout) + self.assertIn("list-collections: lc", result.stdout) + self.assertIn("create-collection: cc", result.stdout) + self.assertIn("delete-collection: dc", result.stdout) + self.assertIn("count: c", result.stdout) + self.assertIn("import: i", result.stdout) + self.assertIn("query: q", result.stdout) + self.assertIn("delete: del", result.stdout) + def test_cli_surfaces_chroma_path_errors(self) -> None: with patch( "chromy.handlers.list_collections.list_collections",