Skip to content

Commit

Permalink
Add a new CLI command: datum format (#1570)
Browse files Browse the repository at this point in the history
### Summary

- This PR resolves https://jira.devtools.intel.com/browse/CVS-144954 and
#1545
- Add a new CLI command: `datum format`. It displays a list of data
format names supported by Datumaro. It can be useful for quick reference
of data format name used for other CLI command such as `datum convert
-if <data-format> -f <data-format>`.

### How to test
Added unit tests as well.

### Checklist
<!-- Put an 'x' in all the boxes that apply -->
- [x] I have added unit tests to cover my changes.​
- [ ] I have added integration tests to cover my changes.​
- [x] I have added the description of my changes into
[CHANGELOG](https://github.com/openvinotoolkit/datumaro/blob/develop/CHANGELOG.md).​
- [x] I have updated the
[documentation](https://github.com/openvinotoolkit/datumaro/tree/develop/docs)
accordingly

### License

- [x] I submit _my code changes_ under the same [MIT
License](https://github.com/openvinotoolkit/datumaro/blob/develop/LICENSE)
that covers the project.
  Feel free to contact the maintainers if that's a concern.
- [x] I have updated the license header for each file (see an example
below).

```python
# Copyright (C) 2024 Intel Corporation
#
# SPDX-License-Identifier: MIT
```

---------

Signed-off-by: Kim, Vinnam <vinnam.kim@intel.com>
  • Loading branch information
vinnamkim authored Jul 24, 2024
1 parent 6ee3b2f commit 1f8e1e7
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## \[unreleased\]
### New features
- Add a new CLI command: datum format
(<https://github.com/openvinotoolkit/datumaro/pull/1570>)

### Enhancements

Expand Down
22 changes: 22 additions & 0 deletions docs/source/docs/command-reference/helper/format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Format

## List Supported Data Formats

This command shows a list of supported import/export data formats in Datumaro.
It is useful on a quick reference of data format name used for other CLI command such as [convert](../context_free/convert.md), [import](../context/sources.md#import-dataset), or [export](../context/export.md#export-datasets). For more detailed guides on each data format, please visit [our Data Formats section](../../data-formats/formats/index.rst).

Usage:

```console
usage: datum format [-h] [-li | -le] [-d DELIMITER]
```

Parameters:
- `-h, --help` - Print the help message and exit.
- `-d DELIMITER, --delimiter DELIMITER` - Seperator used to list data format names (default: `\n`). For example, `datum format -d ','` command displays
```console
Supported import formats:
ade20k2017,ade20k2020,align_celeba,...
```
- `-li, --list-import` - List all supported import data format names
- `-le, --list-export` - List all supported export data format names
9 changes: 9 additions & 0 deletions docs/source/docs/command-reference/helper/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
===============
Helper Commands
===============

.. toctree::
:maxdepth: 1
:glob:

*
4 changes: 2 additions & 2 deletions docs/source/docs/command-reference/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
Overview
========

The command line is split into the separate ``commands`` (:ref:`Context Commands`)
and command ``contexts`` (:ref:`Context-free Commands`).
The command line is split into three groups:
``commands`` (:ref:`Context Commands`), command ``contexts`` (:ref:`Context-free Commands`), and ``helpers`` (:ref:`Helper Commands`).
Contexts group multiple commands related to a specific topic, e.g.
project operations, data source operations etc. Almost all the commands
operate on projects, so the ``project`` context and commands without a context
Expand Down
7 changes: 6 additions & 1 deletion docs/source/docs/explanation/command_line.dot
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ digraph command_line {
"util";
}

subgraph helper {
label = "Helper";
"format";
}

subgraph cluster_model {
label = "Model";
"madd" [label = "add";];
Expand Down Expand Up @@ -70,7 +75,7 @@ digraph command_line {
"split_video";
}

"datum" -> {"convert" "detect" "compare" "dinfo" "download" "explain" "filter" "generate" "merge" "patch" "search" "stats" "transform" "validate"};
"datum" -> {"convert" "detect" "compare" "dinfo" "download" "explain" "filter" "generate" "merge" "patch" "search" "stats" "transform" "validate" "format"};
"datum" -> {"model" "project" "source" "util"};
"model" -> {"madd" "mremove" "run" "minfo"};
"project" -> {"add" "create" "export" "import" "remove"};
Expand Down
1 change: 1 addition & 0 deletions docs/source/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Docs
command-reference/overview
command-reference/context_free/index
command-reference/context/index
command-reference/helper/index

.. toctree::
:maxdepth: 1
Expand Down
22 changes: 19 additions & 3 deletions src/datumaro/cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
send_command_success_info,
)
from ..version import __version__
from . import contexts
from . import contexts, helpers
from .commands import get_non_project_commands, get_project_commands
from .util import add_subparser, make_subcommands_help
from .util.errors import CliException
Expand Down Expand Up @@ -80,9 +80,19 @@ def _get_known_contexts():
]


def _get_helper_commands():
return [
(
"format",
helpers.format,
"List and show information about supported import/export data formats",
),
]


def _get_sensitive_args():
known_contexts = _get_known_contexts()
known_commands = get_project_commands() + get_non_project_commands()
known_commands = get_project_commands() + get_non_project_commands() + _get_helper_commands()

res = {}
for _, command, _ in known_contexts + known_commands:
Expand All @@ -104,6 +114,7 @@ def make_parser():

known_contexts = _get_known_contexts()
known_commands = get_non_project_commands()
known_helpers = _get_helper_commands()

# Argparse doesn't support subparser groups:
# https://stackoverflow.com/questions/32017020/grouping-argparse-subparser-arguments
Expand All @@ -118,6 +129,11 @@ def make_parser():
subcommands_desc += "\n"
subcommands_desc += "Context-free Commands:\n"
subcommands_desc += make_subcommands_help(known_commands, help_line_start)
if known_helpers:
if subcommands_desc:
subcommands_desc += "\n"
subcommands_desc += "Helper Commands:\n"
subcommands_desc += make_subcommands_help(known_helpers, help_line_start)
if subcommands_desc:
subcommands_desc += (
"\nRun '%s COMMAND --help' for more information on a command." % parser.prog
Expand All @@ -126,7 +142,7 @@ def make_parser():
subcommands = parser.add_subparsers(
title=subcommands_desc, description="", help=argparse.SUPPRESS
)
for command_name, command, _ in known_contexts + known_commands:
for command_name, command, _ in known_contexts + known_commands + known_helpers:
if command is not None:
add_subparser(subcommands, command_name, command.build_parser)

Expand Down
5 changes: 5 additions & 0 deletions src/datumaro/cli/helpers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright (C) 2024 Intel Corporation
#
# SPDX-License-Identifier: MIT

from . import format
92 changes: 92 additions & 0 deletions src/datumaro/cli/helpers/format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Copyright (C) 2024 Intel Corporation
#
# SPDX-License-Identifier: MIT

import argparse
import os

from datumaro.cli.util import MultilineFormatter


def build_parser(parser_ctor=argparse.ArgumentParser):
parser = parser_ctor(
help="List supported import/export data formats",
description="""
List supported import/export data format names.
For more detailed guides on each data format,
please visit our documentation website:
https://openvinotoolkit.github.io/datumaro/stable/docs/data-formats/formats
|n
|n
Examples:|n
- List supported import/export data format names:|n
|s|s%(prog)s|n
|n
- List only supported import data format names:|n
|s|s%(prog)s --list-import|n
|n
- List only supported export data format names:|n
|s|s%(prog)s --list-export|n
|n
- List with comma delimiter:|n
|s|s%(prog)s --delimiter ','
""",
formatter_class=MultilineFormatter,
)

group = parser.add_argument_group()
exclusive_group = group.add_mutually_exclusive_group(required=False)

exclusive_group.add_argument(
"-li",
"--list-import",
action="store_true",
help="List all supported import data format names",
)
exclusive_group.add_argument(
"-le",
"--list-export",
action="store_true",
help="List all supported export data format names",
)
parser.add_argument(
"-d",
"--delimiter",
type=str,
default=os.linesep,
help="Seperator used to list data format names (default: \\n)",
)

parser.set_defaults(command=format_command)
return parser


def get_sensitive_args():
return {
format_command: ["list", "show"],
}


def format_command(args: argparse.Namespace) -> None:
from datumaro.components.environment import DEFAULT_ENVIRONMENT

delimiter = args.delimiter

if args.list_import:
builtin_readers = sorted(
set(DEFAULT_ENVIRONMENT.importers) | set(DEFAULT_ENVIRONMENT.extractors)
)
print(delimiter.join(builtin_readers))
return

if args.list_export:
builtin_writers = sorted(DEFAULT_ENVIRONMENT.exporters)
print(delimiter.join(builtin_writers))
return

builtin_readers = sorted(
set(DEFAULT_ENVIRONMENT.importers) | set(DEFAULT_ENVIRONMENT.extractors)
)
builtin_writers = sorted(DEFAULT_ENVIRONMENT.exporters)
print(f"Supported import formats:\n{delimiter.join(builtin_readers)}")
print(f"Supported export formats:\n{delimiter.join(builtin_writers)}")
36 changes: 36 additions & 0 deletions tests/unit/cli/test_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright (C) 2024 Intel Corporation
#
# SPDX-License-Identifier: MIT

from argparse import ArgumentParser, Namespace

import pytest

from datumaro.cli.helpers.format import build_parser, format_command

# from datumaro.cli.__main__ import make_parser


class FormatTest:
def test_build_parser(self):
parser = build_parser(lambda help, **kwargs: ArgumentParser(**kwargs))
assert isinstance(parser, ArgumentParser)

args = parser.parse_args(["--list-import"])
assert args.list_import

args = parser.parse_args(["--list-export"])
assert args.list_export

args = parser.parse_args(["--delimiter", ","])
assert args.delimiter == ","

@pytest.mark.parametrize(
"list_import,list_export", [(True, False), (False, True), (False, False)]
)
def test_format_command(
self, list_import: bool, list_export: bool, capsys: pytest.CaptureFixture
):
format_command(Namespace(delimiter="\n", list_import=list_import, list_export=list_export))
out, _ = capsys.readouterr()
assert "coco" in out

0 comments on commit 1f8e1e7

Please sign in to comment.