diff --git a/.github/workflows/run_test.yaml b/.github/workflows/run_test.yaml index 4f5533f5..95a767f4 100644 --- a/.github/workflows/run_test.yaml +++ b/.github/workflows/run_test.yaml @@ -80,10 +80,16 @@ jobs: PYTHONIOENCODING: utf-8 if: runner.os == 'Windows' - - name: Test datamint-config CLI + - name: Test datamint-config CLI (deprecated alias) run: datamint-config --api-key testapikey timeout-minutes: 1 - env: + env: + PYTHONIOENCODING: utf-8 + + - name: Test datamint config CLI (unified) + run: datamint config --api-key testapikey + timeout-minutes: 1 + env: PYTHONIOENCODING: utf-8 - name: Upload pytest test results diff --git a/README.md b/README.md index 35dc5f4a..7041b141 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ For instance, create the enviroment once with `python3 -m venv datamint-env` and **2. Configure your API key** ```bash -datamint-config +datamint config ``` Follow the prompts (ask your administrator if you don't have a key yet). Environment variable and programmatic options are in the [Setup API Key guide](https://sonanceai.github.io/datamint-python-api/getting_started.html#setup-api-key). @@ -77,7 +77,7 @@ Follow the prompts (ask your administrator if you don't have a key yet). Environ **3. Scaffold a project — the fastest way to start** ```bash -datamint-init +datamint init ``` This is the recommended on-ramp: it asks for a project name and task type (**segmentation**, **classification**, or **detection**), then generates a ready-to-run, numbered set of scripts (`01_upload_data.py` → `06_deploy.py`) — upload data, train, and deploy by running them in order. @@ -103,7 +103,7 @@ results = trainer.fit() | [📖 API Reference](https://sonanceai.github.io/datamint-python-api/client_api.html) | Complete API documentation | | [🔥 PyTorch Integration](https://sonanceai.github.io/datamint-python-api/pytorch_integration.html) | ML workflow integration | | [🧠 Trainer Guide](https://sonanceai.github.io/datamint-python-api/trainer_api.html) | Built-in trainers, trainer lifecycle, and custom model integration | -| [🛠️ Command Line Tools](https://sonanceai.github.io/datamint-python-api/command_line_tools.html) | Full reference for `datamint-upload`, `datamint-init`, and `datamint-config` | +| [🛠️ Command Line Tools](https://sonanceai.github.io/datamint-python-api/command_line_tools.html) | Full reference for `datamint upload`, `datamint init`, and `datamint config` | | [🔒 SSL Troubleshooting](https://sonanceai.github.io/datamint-python-api/ssl_troubleshooting.html) | Fixing `SSLCertVerificationError` | | [📓 Notebooks](notebooks/) | Numbered, runnable tutorials. Start at `01_getting_started` and work through annotations, datasets, experiment tracking, deployment, and a full end-to-end example | diff --git a/datamint/__main__.py b/datamint/__main__.py index 64328745..02380d28 100644 --- a/datamint/__main__.py +++ b/datamint/__main__.py @@ -23,9 +23,9 @@ def _resolve_version() -> str: def _build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( - prog="python -m datamint", + prog="datamint", description="Datamint command-line interface.", - epilog="Available commands: config, upload", + epilog=f"Available commands: {', '.join(_COMMANDS)}.", ) parser.add_argument( "command", @@ -43,11 +43,25 @@ def _build_parser() -> argparse.ArgumentParser: def main() -> None: parser = _build_parser() - # Parse only the first positional argument; leave the rest for the subcommand. - args, remaining = parser.parse_known_args() + argv = sys.argv[1:] + + if not argv: + # Bare "datamint" with no subcommand: show help instead of an argparse error + parser.print_help() + sys.exit(0) + + # Parse only the first token (the command name) so that flags meant for the subcommand + # (e.g. "datamint upload --help") are forwarded untouched instead of being swallowed by + # this top-level parser's own -h/--help/--version handling, which would otherwise trigger + # as soon as it sees them anywhere in the argument list. + args = parser.parse_args(argv[:1]) + remaining = argv[1:] # Replace argv so the subcommand sees only its own arguments. - sys.argv = [f"datamint-{args.command}", *remaining] + # Note: a space (not a hyphen) so nested argparse usage lines read "datamint " + # (argparse's default prog is os.path.basename(sys.argv[0]), which is the string as-is + # when it has no path separator). + sys.argv = [f"datamint {args.command}", *remaining] module_path = _COMMANDS[args.command] try: diff --git a/datamint/client_cmd_tools/datamint_config.py b/datamint/client_cmd_tools/datamint_config.py index c286b56c..200de763 100644 --- a/datamint/client_cmd_tools/datamint_config.py +++ b/datamint/client_cmd_tools/datamint_config.py @@ -11,6 +11,7 @@ from typing_extensions import NotRequired from datamint import configs +from datamint.utils.env import is_legacy_cli_invocation from datamint.utils.logging_utils import ConsoleWrapperHandler, load_cmdline_logging_config _LOGGER = logging.getLogger(__name__) @@ -751,22 +752,29 @@ def main(): console_handlers = [h for h in _USER_LOGGER.handlers if isinstance(h, ConsoleWrapperHandler)] if console_handlers: console = console_handlers[0].console + + if is_legacy_cli_invocation('config'): + console.print( + "[warning]'datamint-config' is deprecated and will be removed in a future " + "release. Use 'datamint config' instead.[/warning]" + ) + parser = argparse.ArgumentParser( description='🔧 Datamint API Configuration Tool', epilog=""" Examples: - datamint-config # Interactive mode - datamint-config --api-key YOUR_KEY # Set API key - datamint-config --list-local-data # Show local cache/data groups and filter selectors - datamint-config --clean-local-data resources + datamint config # Interactive mode + datamint config --api-key YOUR_KEY # Set API key + datamint config --list-local-data # Show local cache/data groups and filter selectors + datamint config --clean-local-data resources # Clean a cache namespace - datamint-config --clean-local-data channel:training-data + datamint config --clean-local-data channel:training-data # Clean cached resources for one upload channel - datamint-config --clean-local-data tag:tutorial + datamint config --clean-local-data tag:tutorial # Clean cached resources matching one tag - datamint-config --clean-local-data "Example Project" + datamint config --clean-local-data "Example Project" # Clean a legacy dataset folder - datamint-config --clean-all-local-data # Clean all local data groups + datamint config --clean-all-local-data # Clean all local data groups More Documentation: https://sonanceai.github.io/datamint-python-api/command_line_tools.html """, diff --git a/datamint/client_cmd_tools/datamint_inference.py b/datamint/client_cmd_tools/datamint_inference.py index d88db030..b2aea4d5 100644 --- a/datamint/client_cmd_tools/datamint_inference.py +++ b/datamint/client_cmd_tools/datamint_inference.py @@ -1,4 +1,4 @@ -"""datamint-inference command-line tool. +"""datamint inference command-line tool. Run local inference with a registered Datamint model against a local file, without writing any Python. Loads the model via MLflow (`models://latest`), builds a @@ -16,6 +16,7 @@ from datamint.client_cmd_tools.datamint_upload import _is_valid_path_argparse, handle_api_key from datamint.exceptions import DatamintException, ItemNotFoundError +from datamint.utils.env import is_legacy_cli_invocation from datamint.utils.logging_utils import ConsoleWrapperHandler, load_cmdline_logging_config _LOGGER = logging.getLogger(__name__) @@ -158,11 +159,11 @@ def _parse_args() -> argparse.Namespace: description='Run local inference with a registered Datamint model against a local file.', epilog=""" Examples: - datamint-inference file.png --model-name MyModel + datamint inference file.png --model-name MyModel # Predict using the model registered as 'MyModel' - datamint-inference file.png --model-name my-model-alias --project MyProject + datamint inference file.png --model-name my-model-alias --project MyProject # Model registered under a different name than its project - datamint-inference file.png --model-name MyModel --output result.png + datamint inference file.png --model-name MyModel --output result.png # Also save a visualization of the predictions More Documentation: https://sonanceai.github.io/datamint-python-api/command_line_tools.html @@ -189,6 +190,12 @@ def main() -> None: load_cmdline_logging_config() CONSOLE = [h for h in _USER_LOGGER.handlers if isinstance(h, ConsoleWrapperHandler)][0].console + if is_legacy_cli_invocation('inference'): + CONSOLE.print( + "[warning]'datamint-inference' is deprecated and will be removed in a future " + "release. Use 'datamint inference' instead.[/warning]" + ) + args = _parse_args() if args.verbose: diff --git a/datamint/client_cmd_tools/datamint_init.py b/datamint/client_cmd_tools/datamint_init.py index c5fb117e..999a6650 100644 --- a/datamint/client_cmd_tools/datamint_init.py +++ b/datamint/client_cmd_tools/datamint_init.py @@ -5,6 +5,8 @@ from rich.prompt import Prompt, Confirm from rich.rule import Rule +from datamint.utils.env import is_legacy_cli_invocation + console = Console() # --------------------------------------------------------------------------- @@ -31,7 +33,7 @@ ```bash pip install datamint -datamint-config --api-key YOUR_API_KEY +datamint config --api-key YOUR_API_KEY ``` """ @@ -483,7 +485,7 @@ ```bash pip install datamint -datamint-config --api-key YOUR_API_KEY +datamint config --api-key YOUR_API_KEY ``` """ @@ -923,7 +925,7 @@ ```bash pip install datamint -datamint-config --api-key YOUR_API_KEY +datamint config --api-key YOUR_API_KEY ``` """ @@ -1443,7 +1445,7 @@ def _generate_segmentation_files(project_name: str) -> dict[str, str]: def _print_header() -> None: console.print() - console.rule("[bold]datamint-init[/bold]") + console.rule("[bold]datamint init[/bold]") console.print() console.print( " This command generates a set of Python scripts that walk you\n" @@ -1465,6 +1467,12 @@ def _print_header() -> None: def main() -> None: + if is_legacy_cli_invocation('init'): + console.print( + "[yellow]'datamint-init' is deprecated and will be removed in a future " + "release. Use 'datamint init' instead.[/yellow]" + ) + _print_header() try: diff --git a/datamint/client_cmd_tools/datamint_train.py b/datamint/client_cmd_tools/datamint_train.py index 04773130..b8c7a568 100644 --- a/datamint/client_cmd_tools/datamint_train.py +++ b/datamint/client_cmd_tools/datamint_train.py @@ -1,4 +1,4 @@ -"""datamint-train command-line tool. +"""datamint train command-line tool. Train a model on a Datamint project using a built-in one-line trainer, without writing any Python. Auto-detects the task (segmentation/classification/detection) and data format @@ -23,6 +23,7 @@ from datamint import Api, configs from datamint.client_cmd_tools.datamint_upload import handle_api_key from datamint.exceptions import DatamintException +from datamint.utils.env import is_legacy_cli_invocation from datamint.utils.logging_utils import ConsoleWrapperHandler, load_cmdline_logging_config if TYPE_CHECKING: @@ -94,7 +95,7 @@ def _detect(console: Console, project_name: str) -> tuple['DatamintBaseDataset', if isinstance(dataset, VideoDataset): raise DatamintTrainCliError( - "Video projects aren't supported by datamint-train yet. " + "Video projects aren't supported by datamint train yet. " "Use the Python SDK (datamint.lightning) to build a custom training loop." ) @@ -255,9 +256,9 @@ def _valid_aliases_for(task: str, fmt: str) -> list[str]: def _print_header(console: Console) -> None: console.print() - console.rule("[bold]datamint-train[/bold]") + console.rule("[bold]datamint train[/bold]") console.print() - console.print(" Answer a few questions and datamint-train will pick a model for you.") + console.print(" Answer a few questions and datamint train will pick a model for you.") console.print() @@ -355,12 +356,12 @@ def _parse_args() -> argparse.Namespace: description='Train a model on a Datamint project using a built-in one-line trainer.', epilog=""" Examples: - datamint-train --project MyProject --model yolox --max-epochs 20 + datamint train --project MyProject --model yolox --max-epochs 20 # Train a specific model - datamint-train --project MyProject # Auto-detect task, data format, and model - datamint-train --project MyProject --dry-run + datamint train --project MyProject # Auto-detect task, data format, and model + datamint train --project MyProject --dry-run # Preview the detected plan without training - datamint-train --interactive # Guided wizard, no flags needed + datamint train --interactive # Guided wizard, no flags needed More Documentation: https://sonanceai.github.io/datamint-python-api/command_line_tools.html#training-a-model """, @@ -399,6 +400,12 @@ def main() -> None: load_cmdline_logging_config() CONSOLE = [h for h in _USER_LOGGER.handlers if isinstance(h, ConsoleWrapperHandler)][0].console + if is_legacy_cli_invocation('train'): + CONSOLE.print( + "[warning]'datamint-train' is deprecated and will be removed in a future " + "release. Use 'datamint train' instead.[/warning]" + ) + args = _parse_args() if args.verbose: diff --git a/datamint/client_cmd_tools/datamint_upload.py b/datamint/client_cmd_tools/datamint_upload.py index 34663d2b..80380ceb 100644 --- a/datamint/client_cmd_tools/datamint_upload.py +++ b/datamint/client_cmd_tools/datamint_upload.py @@ -14,6 +14,7 @@ from datamint import __version__ as datamint_version from datamint import configs from datamint.utils.logging_utils import load_cmdline_logging_config, ConsoleWrapperHandler +from datamint.utils.env import is_legacy_cli_invocation from rich.console import Console import yaml from collections.abc import Iterable @@ -770,6 +771,12 @@ def main(): load_cmdline_logging_config() CONSOLE = [h for h in _USER_LOGGER.handlers if isinstance(h, ConsoleWrapperHandler)][0].console + if is_legacy_cli_invocation('upload'): + CONSOLE.print( + "[warning]'datamint-upload' is deprecated and will be removed in a future " + "release. Use 'datamint upload' instead.[/warning]" + ) + try: args, files_path, segfiles, metadata_files = _parse_args() except Exception as e: diff --git a/datamint/mlflow/env_utils.py b/datamint/mlflow/env_utils.py index 719a46c4..bef8c3ed 100644 --- a/datamint/mlflow/env_utils.py +++ b/datamint/mlflow/env_utils.py @@ -118,14 +118,14 @@ def ensure_mlflow_configured() -> None: if not os.getenv('MLFLOW_TRACKING_URI'): raise ValueError( "MLflow environment not configured. Please either:\n" - "1. Run 'datamint-config --default-url ', or\n" + "1. Run 'datamint config --default-url ', or\n" "2. Set DATAMINT_API_URL environment variable, or\n" "3. Manually set MLFLOW_TRACKING_URI environment variable" ) if not os.getenv('MLFLOW_TRACKING_TOKEN'): raise ValueError( "MLflow environment not configured. Please either:\n" - "1. Run 'datamint-config', or\n" + "1. Run 'datamint config', or\n" "2. Set DATAMINT_API_KEY environment variable, or\n" "3. Manually set MLFLOW_TRACKING_TOKEN environment variable" ) diff --git a/datamint/utils/env.py b/datamint/utils/env.py index b633a322..35bfba4e 100644 --- a/datamint/utils/env.py +++ b/datamint/utils/env.py @@ -25,3 +25,10 @@ def ensure_asyncio_loop(): import nest_asyncio nest_asyncio.apply() _ASYNCIO_LOOP_PATCHED = True + + +def is_legacy_cli_invocation(command: str) -> bool: + """Check if the current process was launched via the deprecated `datamint-` script.""" + import os + import sys + return os.path.basename(sys.argv[0]) == f"datamint-{command}" diff --git a/dev/README.md b/dev/README.md index 6c4d5013..e556bb22 100644 --- a/dev/README.md +++ b/dev/README.md @@ -15,7 +15,7 @@ Quick reference for developers working on the `datamint-python-api` SDK. ## Configuration -The SDK uses a local configuration file for authentication and settings. When the user runs [`datamint-config`](./datamint/client_cmd_tools/datamint_config.py), configuration is stored in `~/.config/datamintapi/datamintapi.yaml` (via [PlatformDirs](https://pypi.org/project/platformdirs/)). +The SDK uses a local configuration file for authentication and settings. When the user runs [`datamint config`](./datamint/client_cmd_tools/datamint_config.py), configuration is stored in `~/.config/datamintapi/datamintapi.yaml` (via [PlatformDirs](https://pypi.org/project/platformdirs/)). ## Module Structure @@ -39,7 +39,7 @@ datamint/ │ ├── flavors/ # Model flavors and prediction routing │ ├── tracking/ # Custom DatamintStore │ └── artifact/ # DatamintArtifactsRepository plugin -├── client_cmd_tools/ # CLI tools (datamint-upload, datamint-config) +├── client_cmd_tools/ # CLI tools (datamint upload, datamint config) └── utils/ # General Utilities ``` diff --git a/docs/source/command_line_tools.rst b/docs/source/command_line_tools.rst index 7d29cc5b..bd6e1e5f 100644 --- a/docs/source/command_line_tools.rst +++ b/docs/source/command_line_tools.rst @@ -3,14 +3,23 @@ Command-line tools ================== -To see if the Datamint command-line tools were installed correctly, run: +All Datamint command-line tools are invoked through a single ``datamint`` command, followed +by a subcommand and its arguments — the same ``tool ARGS`` pattern used by tools +like ``docker``, ``git``, and ``pip``: .. code-block:: bash - datamint-config --help + datamint config --help .. note:: - If the ``datamint-config`` command does not work, try: + Older versions used a separate hyphenated script per command (``datamint-config``, + ``datamint-upload``, ``datamint-init``, ``datamint-train``, ``datamint-inference``). + These still work for backward compatibility, but are deprecated — each prints a warning + telling you to switch to the ``datamint `` form, and they will be removed in a + future release. + +.. note:: + If the ``datamint config`` command does not work, try: .. code-block:: bash @@ -20,26 +29,27 @@ You should see this in the first line: .. code-block:: bash - usage: datamint-config [-h] [--api-key API_KEY] [--default-url DEFAULT_URL] [-i] [...] + usage: datamint config [-h] [--api-key API_KEY] [--default-url DEFAULT_URL] [-i] [...] -There are three command-line tools available: +There are five command-line tools available: -- ``datamint-config``: To configure the Datamint API key and URL. -- ``datamint-upload``: To upload DICOM, NIfTI, video, image, and segmentation files to the Datamint server. -- ``datamint-train``: To train a model on a Datamint project using a built-in one-line trainer. -- ``datamint-inference``: To run local inference with a registered Datamint model against a local file. +- ``datamint config``: To configure the Datamint API key and URL. +- ``datamint upload``: To upload DICOM, NIfTI, video, image, and segmentation files to the Datamint server. +- ``datamint init``: To scaffold a ready-to-run project (upload, train, and deploy scripts). +- ``datamint train``: To train a model on a Datamint project using a built-in one-line trainer. +- ``datamint inference``: To run local inference with a registered Datamint model against a local file. Configuring the Datamint settings --------------------------------- -The ``datamint-config`` command-line tool is useful for configuring the Datamint API key and URL, +The ``datamint config`` command-line tool is useful for configuring the Datamint API key and URL, consequently avoiding the need to manually pass them as arguments or environment variables to the other commands later. To manage Datamint configurations, just run .. code-block:: bash - datamint-config + datamint config It starts an interactive prompt, guiding you through the configuration process. @@ -47,7 +57,7 @@ To set the API key without the interactive prompt, use the command-line option ` .. code-block:: bash - datamint-config --api-key YOUR_API_KEY + datamint config --api-key YOUR_API_KEY Local data management +++++++++++++++++++++ @@ -58,24 +68,24 @@ instead of individual cached resources, so cleanup happens at that higher level: .. code-block:: bash - datamint-config --list-local-data # List all local data namespaces - datamint-config --clean-local-data resources # Clean resource cache - datamint-config --clean-local-data annotations # Clean annotation cache - datamint-config --clean-all-local-data # Clean all local data + datamint config --list-local-data # List all local data namespaces + datamint config --clean-local-data resources # Clean resource cache + datamint config --clean-local-data annotations # Clean annotation cache + datamint config --clean-all-local-data # Clean all local data Uploading DICOMs/resources to Datamint server --------------------------------------------- To upload DICOM files to the Datamint server, use the -``datamint-upload`` command. For example, to upload all the DICOM files in the +``datamint upload`` command. For example, to upload all the DICOM files in the ``/path/to/dicom_files`` directory, run: .. code-block:: bash - datamint-upload /path/to/dicom_files/ + datamint upload /path/to/dicom_files/ .. note:: - If the ``datamint-upload`` command does not work, try: + If the ``datamint upload`` command does not work, try: .. code-block:: bash @@ -87,39 +97,39 @@ retain the personal identifiable information (PII) in the DICOM files, use the .. code-block:: bash - datamint-upload /path/to/dicom_files/ --retain-pii + datamint upload /path/to/dicom_files/ --retain-pii To upload all DICOMs in a directory and also in its subdirectories, you can use the recursive option ``-r`` flag: .. code-block:: bash - datamint-upload /path/to/dicom_files/ -r + datamint upload /path/to/dicom_files/ -r In Datamint, you can use channels to organize your DICOMs/resources. In that case, use the ``--channel`` flag: .. code-block:: bash - datamint-upload /path/to/video.mp4 --channel "CT scans" + datamint upload /path/to/video.mp4 --channel "CT scans" To upload resources, associating them with a tag, run: .. code-block:: bash - datamint-upload /path/to/dicom_files --tag "my_tag" + datamint upload /path/to/dicom_files --tag "my_tag" You can specify multiple tags by repeating the ``--tag`` flag: .. code-block:: bash - datamint-upload /path/to/dicom_files --tag "tag1" --tag "tag2" + datamint upload /path/to/dicom_files --tag "tag1" --tag "tag2" You can bypass the inbox/review and directly publish your resources with the ``--publish`` flag: .. code-block:: bash - datamint-upload /path/to/resource_file --publish + datamint upload /path/to/resource_file --publish Example using include and exclude extensions options: +++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -128,13 +138,13 @@ To upload only DICOM files, run: .. code-block:: bash - datamint-upload /root_dir --include-extensions dcm + datamint upload /root_dir --include-extensions dcm To upload all files except the .txt and .csv files, run: .. code-block:: bash - datamint-upload /root_dir --exclude-extensions txt csv + datamint upload /root_dir --exclude-extensions txt csv Uploading segmentations along with the resources +++++++++++++++++++++++++++++++++++++++++++++++++ @@ -143,7 +153,7 @@ To upload segmentations along with the resources, you can use .. code-block:: bash - datamint-upload data/OAI_CARE/dicoms/ -r --segmentation_path data/OAI_CARE/segmentations/ --publish + datamint upload data/OAI_CARE/dicoms/ -r --segmentation_path data/OAI_CARE/segmentations/ --publish Both ``data/OAI_CARE/dicoms/`` and ``data/OAI_CARE/segmentations/`` must obey the same folder structure. Both folders and files can have arbitrary names. @@ -171,7 +181,7 @@ You can provide the segmentation names file with the ``--segmentation_names`` fl .. code-block:: bash - datamint-upload data/OAI_CARE/dicoms/ -r --segmentation_path data/OAI_CARE/segmentations/ --segmentation_names segmentation_names.yaml --publish + datamint upload data/OAI_CARE/dicoms/ -r --segmentation_path data/OAI_CARE/segmentations/ --segmentation_names segmentation_names.yaml --publish Associating uploaded segmentations with a deployed model ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -181,7 +191,7 @@ If the uploaded segmentations were produced by a deployed Datamint model, use .. code-block:: bash - datamint-upload data/OAI_CARE/dicoms/ -r --segmentation_path data/OAI_CARE/segmentations/ --segmentation_names segmentation_names.yaml --ai-model knee-segmentation-v2 --publish + datamint upload data/OAI_CARE/dicoms/ -r --segmentation_path data/OAI_CARE/segmentations/ --segmentation_names segmentation_names.yaml --ai-model knee-segmentation-v2 --publish The value passed to ``--ai-model`` must match the name of an existing deployed model on the server. This option only affects uploaded segmentations; resource @@ -195,13 +205,13 @@ For example, if you have ``image.nii.gz``, it will automatically include ``image .. code-block:: bash - datamint-upload /path/to/nifti_files/ -r + datamint upload /path/to/nifti_files/ -r This feature can be disabled with ``--no-auto-detect-json`` flag: .. code-block:: bash - datamint-upload /path/to/nifti_files/ -r --no-auto-detect-json + datamint upload /path/to/nifti_files/ -r --no-auto-detect-json Checking uploaded segmentations +++++++++++++++++++++++++++++++ @@ -218,7 +228,7 @@ To check if the segmentations were uploaded correctly, you can see some informat All available options +++++++++++++++++++++ -See all available options by running ``datamint-upload --help``: +See all available options by running ``datamint upload --help``: -h, --help show this help message and exit --path FILE Path to the resource file(s) or a directory (alternative to positional argument) @@ -266,47 +276,47 @@ See all available options by running ``datamint-upload --help``: Training a model ----------------- -The ``datamint-train`` command-line tool trains a model on a Datamint project without +The ``datamint train`` command-line tool trains a model on a Datamint project without writing any Python. It auto-detects the task (segmentation, classification, or detection) and data format (2D or 3D) from the project's annotations and resources, then picks a sensible default model if you don't specify one: .. code-block:: bash - datamint-train --project MyProject --model yolox --max-epochs 20 - datamint-train --project MyProject # auto-detect task, format, and model + datamint train --project MyProject --model yolox --max-epochs 20 + datamint train --project MyProject # auto-detect task, format, and model To preview the detected plan (task, format, model, hyperparameters) without training, use ``--dry-run``: .. code-block:: bash - datamint-train --project MyProject --dry-run + datamint train --project MyProject --dry-run Or run the guided wizard, which walks you through the same choices and confirms the plan before starting: .. code-block:: bash - datamint-train --interactive + datamint train --interactive Advanced training options (custom losses, transforms, encoders, ``trainer_kwargs``, etc.) are intentionally not exposed here — use the Python SDK instead, see :doc:`Training your Model `. -See all available options by running ``datamint-train --help``. +See all available options by running ``datamint train --help``. Running local inference ------------------------ -The ``datamint-inference`` command-line tool runs a registered Datamint model against a +The ``datamint inference`` command-line tool runs a registered Datamint model against a local file, without writing any Python. It loads the model via MLflow (``models://latest``), runs it against the given file, and prints the resulting predictions: .. code-block:: bash - datamint-inference file.png --model-name MyModel + datamint inference file.png --model-name MyModel Models are looked up by project. By default, the project name is assumed to be the same as ``--model-name``. If the model was registered under a different project, pass @@ -314,13 +324,13 @@ as ``--model-name``. If the model was registered under a different project, pass .. code-block:: bash - datamint-inference file.png --model-name my-model-alias --project MyProject + datamint inference file.png --model-name my-model-alias --project MyProject To also save a visualization of the predictions overlaid on the input file, use ``--output``: .. code-block:: bash - datamint-inference file.png --model-name MyModel --output result.png + datamint inference file.png --model-name MyModel --output result.png -See all available options by running ``datamint-inference --help``. \ No newline at end of file +See all available options by running ``datamint inference --help``. \ No newline at end of file diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index fa851ddc..f721aa72 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -32,12 +32,12 @@ Verify your installation Scaffold your first project =========================== -``datamint-init`` generates a ready-to-run set of numbered scripts tailored to your task +``datamint init`` generates a ready-to-run set of numbered scripts tailored to your task (detection, segmentation, or classification): .. code-block:: bash - datamint-init + datamint init It asks for a project name and task type, then writes six scripts into a new directory (upload data, explore, build a dataset, train, evaluate, and deploy), so you can follow @@ -95,4 +95,4 @@ Troubleshooting .. code-block:: bash - datamint-config + datamint config diff --git a/docs/source/index.rst b/docs/source/index.rst index 7770bfc1..7149e5e6 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -59,7 +59,7 @@ Configure your API access: .. code-block:: bash - datamint-config + datamint config Start using the API: diff --git a/docs/source/setup_api_key.rst b/docs/source/setup_api_key.rst index d64d7acd..d5a6faa5 100644 --- a/docs/source/setup_api_key.rst +++ b/docs/source/setup_api_key.rst @@ -35,7 +35,7 @@ Once you have your API key, choose one of the following options: .. code-block:: bash - datamint-config --api-key YOUR_API_KEY + datamint config --api-key YOUR_API_KEY **Option 2: Setting an environment variable** diff --git a/notebooks/01_getting_started/01_upload_data.ipynb b/notebooks/01_getting_started/01_upload_data.ipynb index a56d309f..ceecea8e 100644 --- a/notebooks/01_getting_started/01_upload_data.ipynb +++ b/notebooks/01_getting_started/01_upload_data.ipynb @@ -39,7 +39,7 @@ "- `api.channels` - Channel organization\n", "- `api.users` - User management\n", "\n", - "Make sure you've run `datamint-config` in your terminal first." + "Make sure you've run `datamint config` in your terminal first." ] }, { @@ -51,7 +51,7 @@ "from datamint import Api\n", "from pathlib import Path\n", "# Creates a connection with the server.\n", - "# Don't forget to run `datamint-config` in a terminal, if you haven't already.\n", + "# Don't forget to run `datamint config` in a terminal, if you haven't already.\n", "# Or use api_key parameter in Api()\n", "api = Api()" ] diff --git a/notebooks/02_annotations/02_geometry_annotations.ipynb b/notebooks/02_annotations/02_geometry_annotations.ipynb index ee1d531d..fca17be1 100644 --- a/notebooks/02_annotations/02_geometry_annotations.ipynb +++ b/notebooks/02_annotations/02_geometry_annotations.ipynb @@ -45,7 +45,7 @@ "metadata": {}, "outputs": [], "source": [ - "# !datamint-config --api-key MY_API_KEY" + "# !datamint config --api-key MY_API_KEY" ] }, { diff --git a/pyproject.toml b/pyproject.toml index 138e1dc8..e4dd3dea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,7 @@ requires-python = ">=3.10" readme = "README.md" [project.scripts] +datamint = 'datamint.__main__:main' datamint-upload = 'datamint.client_cmd_tools.datamint_upload:main' datamint-config = 'datamint.client_cmd_tools.datamint_config:main' datamint-init = 'datamint.client_cmd_tools.datamint_init:main' diff --git a/tests/test_datamint_config.py b/tests/test_datamint_config.py index 7bd11bd7..dcd22112 100644 --- a/tests/test_datamint_config.py +++ b/tests/test_datamint_config.py @@ -117,6 +117,24 @@ def test_command_line_api_key_argument(self, mock_set_values) -> None: # Verify the API key was set with correct key mock_set_values.assert_called_once() + @patch('datamint.configs.set_values') + def test_legacy_hyphenated_invocation_prints_deprecation_warning(self, mock_set_values, capsys) -> None: + """Invoking via the old 'datamint-config' script name should warn.""" + with patch('sys.argv', ['datamint-config', '--api-key', 'test_key']): + from datamint.client_cmd_tools.datamint_config import main + main() + + assert 'deprecated' in capsys.readouterr().out + + @patch('datamint.configs.set_values') + def test_unified_invocation_does_not_print_deprecation_warning(self, mock_set_values, capsys) -> None: + """Invoking via the unified 'datamint config' dispatch should not warn.""" + with patch('sys.argv', ['datamint config', '--api-key', 'test_key']): + from datamint.client_cmd_tools.datamint_config import main + main() + + assert 'deprecated' not in capsys.readouterr().out + def test_show_configurations_functionality(self) -> None: """Test show_all_configurations without user interaction.""" from datamint.client_cmd_tools.datamint_config import show_all_configurations