# Copyright (C) 2021-2022 Intel Corporation # Copyright (C) 2022 CVAT.ai Corporation # # SPDX-License-Identifier: MIT import argparse import getpass import json import logging import os from distutils.util import strtobool from cvat_sdk.core.proxies.tasks import ResourceType from .version import VERSION def get_auth(s): """Parse USER[:PASS] strings and prompt for password if none was supplied.""" user, _, password = s.partition(":") password = password or os.environ.get("PASS") or getpass.getpass() return user, password def parse_label_arg(s): """If s is a file load it as JSON, otherwise parse s as JSON.""" if os.path.exists(s): with open(s, "r") as fp: return json.load(fp) else: return json.loads(s) def parse_resource_type(s: str) -> ResourceType: try: return ResourceType[s.upper()] except KeyError: return s def make_cmdline_parser() -> argparse.ArgumentParser: ####################################################################### # Command line interface definition ####################################################################### parser = argparse.ArgumentParser( description="Perform common operations related to CVAT tasks.\n\n" ) parser.add_argument("--version", action="version", version=VERSION) task_subparser = parser.add_subparsers(dest="action") ####################################################################### # Positional arguments ####################################################################### parser.add_argument( "--auth", type=get_auth, metavar="USER:[PASS]", default=getpass.getuser(), help="""defaults to the current user and supports the PASS environment variable or password prompt (default user: %(default)s).""", ) parser.add_argument( "--server-host", type=str, default="localhost", help="host (default: %(default)s)" ) parser.add_argument( "--server-port", type=int, default="8080", help="port (default: %(default)s)" ) parser.add_argument( "--https", default=False, action="store_true", help="force https connection (default: try to detect automatically)", ) parser.add_argument( "--debug", action="store_const", dest="loglevel", const=logging.DEBUG, default=logging.INFO, help="show debug output", ) ####################################################################### # Create ####################################################################### task_create_parser = task_subparser.add_parser( "create", description="""Create a new CVAT task. To create a task, you need to specify labels using the --labels argument or attach the task to an existing project using the --project_id argument.""", ) task_create_parser.add_argument("name", type=str, help="name of the task") task_create_parser.add_argument( "resource_type", default="local", choices=list(ResourceType), type=parse_resource_type, help="type of files specified", ) task_create_parser.add_argument("resources", type=str, help="list of paths or URLs", nargs="+") task_create_parser.add_argument( "--annotation_path", default="", type=str, help="path to annotation file" ) task_create_parser.add_argument( "--annotation_format", default="CVAT 1.1", type=str, help="format of the annotation file being uploaded, e.g. CVAT 1.1", ) task_create_parser.add_argument( "--bug_tracker", "--bug", default=None, type=str, help="bug tracker URL" ) task_create_parser.add_argument( "--chunk_size", default=None, type=int, help="the number of frames per chunk" ) task_create_parser.add_argument( "--completion_verification_period", dest="status_check_period", default=20, type=float, help="""number of seconds to wait until checking if data compression finished (necessary before uploading annotations)""", ) task_create_parser.add_argument( "--copy_data", default=False, action="store_true", help="""set the option to copy the data, only used when resource type is share (default: %(default)s)""", ) task_create_parser.add_argument( "--dataset_repository_url", default="", type=str, help=( "git repository to store annotations e.g." " https://github.com/user/repos [annotation/]" ), ) task_create_parser.add_argument( "--frame_step", default=None, type=int, help="""set the frame step option in the advanced configuration when uploading image series or videos (default: %(default)s)""", ) task_create_parser.add_argument( "--image_quality", default=70, type=int, help="""set the image quality option in the advanced configuration when creating tasks.(default: %(default)s)""", ) task_create_parser.add_argument( "--labels", default="[]", type=parse_label_arg, help="string or file containing JSON labels specification", ) task_create_parser.add_argument( "--lfs", default=False, action="store_true", help="using lfs for dataset repository (default: %(default)s)", ) task_create_parser.add_argument( "--project_id", default=None, type=int, help="project ID if project exists" ) task_create_parser.add_argument( "--overlap", default=None, type=int, help="the number of intersected frames between different segments", ) task_create_parser.add_argument( "--segment_size", default=None, type=int, help="the number of frames in a segment" ) task_create_parser.add_argument( "--sorting-method", default="lexicographical", choices=["lexicographical", "natural", "predefined", "random"], help="""data soring method (default: %(default)s)""", ) task_create_parser.add_argument( "--start_frame", default=None, type=int, help="the start frame of the video" ) task_create_parser.add_argument( "--stop_frame", default=None, type=int, help="the stop frame of the video" ) task_create_parser.add_argument( "--use_cache", action="store_true", help="""use cache""" # automatically sets default=False ) task_create_parser.add_argument( "--use_zip_chunks", action="store_true", # automatically sets default=False help="""zip chunks before sending them to the server""", ) ####################################################################### # Delete ####################################################################### delete_parser = task_subparser.add_parser("delete", description="Delete a CVAT task.") delete_parser.add_argument("task_ids", type=int, help="list of task IDs", nargs="+") ####################################################################### # List ####################################################################### ls_parser = task_subparser.add_parser( "ls", description="List all CVAT tasks in simple or JSON format." ) ls_parser.add_argument( "--json", dest="use_json_output", default=False, action="store_true", help="output JSON data", ) ####################################################################### # Frames ####################################################################### frames_parser = task_subparser.add_parser( "frames", description="Download all frame images for a CVAT task." ) frames_parser.add_argument("task_id", type=int, help="task ID") frames_parser.add_argument( "frame_ids", type=int, help="list of frame IDs to download", nargs="+" ) frames_parser.add_argument( "--outdir", type=str, default="", help="directory to save images (default: CWD)" ) frames_parser.add_argument( "--quality", type=str, choices=("original", "compressed"), default="original", help="choose quality of images (default: %(default)s)", ) ####################################################################### # Dump ####################################################################### dump_parser = task_subparser.add_parser( "dump", description="Download annotations for a CVAT task." ) dump_parser.add_argument("task_id", type=int, help="task ID") dump_parser.add_argument("filename", type=str, help="output file") dump_parser.add_argument( "--format", dest="fileformat", type=str, default="CVAT for images 1.1", help="annotation format (default: %(default)s)", ) dump_parser.add_argument( "--completion_verification_period", dest="status_check_period", default=3, type=float, help="number of seconds to wait until checking if dataset building finished", ) dump_parser.add_argument( "--with-images", type=strtobool, default=False, dest="include_images", help="Whether to include images or not (default: %(default)s)", ) ####################################################################### # Upload Annotations ####################################################################### upload_parser = task_subparser.add_parser( "upload", description="Upload annotations for a CVAT task." ) upload_parser.add_argument("task_id", type=int, help="task ID") upload_parser.add_argument("filename", type=str, help="upload file") upload_parser.add_argument( "--format", dest="fileformat", type=str, default="CVAT 1.1", help="annotation format (default: %(default)s)", ) ####################################################################### # Export task ####################################################################### export_task_parser = task_subparser.add_parser("export", description="Export a CVAT task.") export_task_parser.add_argument("task_id", type=int, help="task ID") export_task_parser.add_argument("filename", type=str, help="output file") export_task_parser.add_argument( "--completion_verification_period", dest="status_check_period", default=3, type=float, help="time interval between checks if archive building has been finished, in seconds", ) ####################################################################### # Import task ####################################################################### import_task_parser = task_subparser.add_parser("import", description="Import a CVAT task.") import_task_parser.add_argument("filename", type=str, help="upload file") import_task_parser.add_argument( "--completion_verification_period", dest="status_check_period", default=3, type=float, help="time interval between checks if archive proessing was finished, in seconds", ) return parser def get_action_args( parser: argparse.ArgumentParser, parsed_args: argparse.Namespace ) -> argparse.Namespace: # FIXME: a hacky way to remove unnecessary args action_args = dict(vars(parsed_args)) for action in parser._actions: action_args.pop(action.dest, None) # remove default args for k, v in dict(action_args).items(): if v is None: action_args.pop(k, None) return argparse.Namespace(**action_args)