CLI package (#59)

main
Maxim Zhiltsov 4 years ago committed by GitHub
parent bc9fc45eef
commit fd4a1307b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4,7 +4,7 @@ branch = true
source = source =
cvat/apps/ cvat/apps/
utils/cli/ cvat-cli/
utils/dataset_manifest utils/dataset_manifest
omit = omit =

@ -133,7 +133,7 @@ jobs:
CONTAINER_COVERAGE_DATA_DIR: "/coverage_data" CONTAINER_COVERAGE_DATA_DIR: "/coverage_data"
run: | run: |
docker-compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml run cvat_ci /bin/bash \ docker-compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml run cvat_ci /bin/bash \
-c 'coverage run -a manage.py test cvat/apps utils/cli -k 'tasks_id' -k 'lambda' -k 'share' && mv .coverage ${CONTAINER_COVERAGE_DATA_DIR}' -c 'coverage run -a manage.py test cvat/apps cvat-cli -k 'tasks_id' -k 'lambda' -k 'share' && mv .coverage ${CONTAINER_COVERAGE_DATA_DIR}'
docker-compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml run cvat_ci /bin/bash \ docker-compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml run cvat_ci /bin/bash \
-c 'cd cvat-data && npm ci --ignore-scripts && cd ../cvat-core && npm ci --ignore-scripts && npm run test && mv ./reports/coverage/lcov.info ${CONTAINER_COVERAGE_DATA_DIR} && chmod a+rwx ${CONTAINER_COVERAGE_DATA_DIR}/lcov.info' -c 'cd cvat-data && npm ci --ignore-scripts && cd ../cvat-core && npm ci --ignore-scripts && npm run test && mv ./reports/coverage/lcov.info ${CONTAINER_COVERAGE_DATA_DIR} && chmod a+rwx ${CONTAINER_COVERAGE_DATA_DIR}/lcov.info'

@ -169,7 +169,7 @@
"--settings", "--settings",
"cvat.settings.testing", "cvat.settings.testing",
"cvat/apps", "cvat/apps",
"utils/cli" "cvat-cli/"
], ],
"django": true, "django": true,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Project/task backups uploading via chunk uploads (<https://github.com/cvat-ai/cvat/pull/9>) - Project/task backups uploading via chunk uploads (<https://github.com/cvat-ai/cvat/pull/9>)
- Fixed UX bug when jobs pagination is reset after changing a job (<https://github.com/cvat-ai/cvat/pull/42>) - Fixed UX bug when jobs pagination is reset after changing a job (<https://github.com/cvat-ai/cvat/pull/42>)
- Progressbars in CLI for file uploading and downloading (<https://github.com/cvat-ai/cvat/pull/46>) - Progressbars in CLI for file uploading and downloading (<https://github.com/cvat-ai/cvat/pull/46>)
- `utils/cli` changed to `cvat-cli` package (<https://github.com/cvat-ai/cvat/pull/59>)
### Changed ### Changed
- Bumped nuclio version to 1.8.14 (<https://github.com/cvat-ai/cvat/pull/29>) - Bumped nuclio version to 1.8.14 (<https://github.com/cvat-ai/cvat/pull/29>)

@ -147,7 +147,6 @@ COPY --chown=${USER} ssh ${HOME}/.ssh
COPY --chown=${USER} supervisord.conf mod_wsgi.conf wait-for-it.sh manage.py ${HOME}/ COPY --chown=${USER} supervisord.conf mod_wsgi.conf wait-for-it.sh manage.py ${HOME}/
COPY --chown=${USER} cvat/ ${HOME}/cvat COPY --chown=${USER} cvat/ ${HOME}/cvat
COPY --chown=${USER} utils/ ${HOME}/utils COPY --chown=${USER} utils/ ${HOME}/utils
COPY --chown=${USER} tests/ ${HOME}/tests
# RUN all commands below as 'django' user # RUN all commands below as 'django' user
USER ${USER} USER ${USER}

@ -22,14 +22,14 @@ RUN apt-get update && \
rm -rf /var/lib/apt/lists/*; rm -rf /var/lib/apt/lists/*;
COPY cvat/requirements/ /tmp/cvat/requirements/ COPY cvat/requirements/ /tmp/cvat/requirements/
COPY utils/cli/requirements/ /tmp/utils/cli/requirements/ COPY cvat-cli ${HOME}/cvat-cli
RUN DATUMARO_HEADLESS=1 python3 -m pip install --no-cache-dir -r /tmp/cvat/requirements/${DJANGO_CONFIGURATION}.txt && \ RUN DATUMARO_HEADLESS=1 python3 -m pip install --no-cache-dir -r /tmp/cvat/requirements/${DJANGO_CONFIGURATION}.txt && \
python3 -m pip install --no-cache-dir -r /tmp/utils/cli/requirements/testing.txt && \ python3 -m pip install --no-cache-dir -r ${HOME}/cvat-cli/requirements/testing.txt && \
python3 -m pip install --no-cache-dir ${HOME}/cvat-cli && \
python3 -m pip install --no-cache-dir coveralls python3 -m pip install --no-cache-dir coveralls
RUN gem install coveralls-lcov RUN gem install coveralls-lcov
COPY utils ${HOME}/utils
COPY cvat-core ${HOME}/cvat-core COPY cvat-core ${HOME}/cvat-core
COPY cvat-data ${HOME}/cvat-data COPY cvat-data ${HOME}/cvat-data
COPY package*.json ${HOME}/ COPY package*.json ${HOME}/

@ -0,0 +1,2 @@
include README.md
include requirements/base.txt

@ -0,0 +1,11 @@
# Command-line client for CVAT
## Installation
`pip install cvat-cli/`
## Usage
```bash
$ cvat-cli --help
```

@ -0,0 +1,19 @@
# Developer guide
Install testing requirements:
```bash
pip install -r requirements/testing.txt
```
Run unit tests:
```
cd cvat/
python manage.py test --settings cvat.settings.testing cvat-cli/
```
Install package in the editable mode:
```bash
pip install -e .
```

@ -0,0 +1,4 @@
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

@ -0,0 +1,4 @@
-r base.txt
# We depend on the server in the tests
-r ../../cvat/requirements/testing.txt

@ -0,0 +1,67 @@
# Copyright (C) 2022 Intel Corporation
#
# SPDX-License-Identifier: MIT
import os.path as osp
import re
import setuptools
def find_version(project_dir=None):
if not project_dir:
project_dir = osp.dirname(osp.abspath(__file__))
file_path = osp.join(project_dir, "version.py")
with open(file_path, "r") as version_file:
version_text = version_file.read()
# PEP440:
# https://www.python.org/dev/peps/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions
pep_regex = r"([1-9]\d*!)?(0|[1-9]\d*)(\.(0|[1-9]\d*))*((a|b|rc)(0|[1-9]\d*))?(\.post(0|[1-9]\d*))?(\.dev(0|[1-9]\d*))?"
version_regex = r"VERSION\s*=\s*.(" + pep_regex + ")."
match = re.match(version_regex, version_text)
if not match:
raise RuntimeError("Failed to find version string in '%s'" % file_path)
version = version_text[match.start(1) : match.end(1)]
return version
BASE_REQUIREMENTS_FILE = "requirements/base.txt"
def parse_requirements(filename=BASE_REQUIREMENTS_FILE):
with open(filename) as fh:
return fh.readlines()
BASE_REQUIREMENTS = parse_requirements(BASE_REQUIREMENTS_FILE)
with open("README.md", "r") as fh:
long_description = fh.read()
setuptools.setup(
name="cvat-cli",
version=find_version(project_dir="src/cvat_cli"),
description="Command-line client for CVAT",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/openvinotoolkit/cvat/",
package_dir={"": "src"},
packages=setuptools.find_packages(where='src'),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires=">=3.7",
install_requires=BASE_REQUIREMENTS,
entry_points={
"console_scripts": [
"cvat-cli=cvat_cli.__main__:main",
],
},
include_package_data=True,
)

@ -0,0 +1,3 @@
# Copyright (C) 2020-2022 Intel Corporation
#
# SPDX-License-Identifier: MIT

@ -1,12 +1,13 @@
#!/usr/bin/env python3 # Copyright (C) 2020-2022 Intel Corporation
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
import logging import logging
import requests import requests
import sys import sys
from http.client import HTTPConnection from http.client import HTTPConnection
from core.core import CLI, CVAT_API_V2 from cvat_cli.core.core import CLI, CVAT_API_V2
from core.definition import parser from cvat_cli.core.definition import parser
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -45,6 +46,8 @@ def main():
requests.exceptions.RequestException) as e: requests.exceptions.RequestException) as e:
log.critical(e) log.critical(e)
return 0
if __name__ == '__main__': if __name__ == '__main__':
main() sys.exit(main())

@ -1,3 +1,6 @@
# Copyright (C) 2020-2022 Intel Corporation
#
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
from .definition import parser, ResourceType # noqa from .definition import parser, ResourceType # noqa
from .core import CLI, CVAT_API_V2 # noqa from .core import CLI, CVAT_API_V2 # noqa

@ -1,4 +1,4 @@
# Copyright (C) 2021 Intel Corporation # Copyright (C) 2021-2022 Intel Corporation
# #
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
import argparse import argparse
@ -7,6 +7,7 @@ import json
import logging import logging
import os import os
from enum import Enum from enum import Enum
from ..version import VERSION
def get_auth(s): def get_auth(s):
@ -53,6 +54,8 @@ class ResourceType(Enum):
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Perform common operations related to CVAT tasks.\n\n' 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') task_subparser = parser.add_subparsers(dest='action')
####################################################################### #######################################################################

@ -0,0 +1,3 @@
# Copyright (C) 2020-2022 Intel Corporation
#
# SPDX-License-Identifier: MIT

@ -16,7 +16,7 @@ from datumaro.util.scope import scoped, on_exit_do
import cvat.apps.engine.log as log import cvat.apps.engine.log as log
from cvat.apps.engine.tests.test_rest_api import (create_db_users, from cvat.apps.engine.tests.test_rest_api import (create_db_users,
generate_image_file) generate_image_file)
from utils.cli.core import CLI, CVAT_API_V2, ResourceType from cvat_cli.core import CLI, CVAT_API_V2, ResourceType
from tqdm import tqdm from tqdm import tqdm
@ -24,7 +24,7 @@ class TestCLI(APITestCase):
def setUp(self): def setUp(self):
self._stdout_handler = redirect_stdout(io.StringIO()) self._stdout_handler = redirect_stdout(io.StringIO())
mock_stdout = self._stdout_handler.__enter__() mock_stdout = self._stdout_handler.__enter__()
log = logging.getLogger("utils.cli") log = logging.getLogger("cvat_cli")
log.propagate = False log.propagate = False
log.setLevel(logging.INFO) log.setLevel(logging.INFO)
log.handlers.clear() log.handlers.clear()
@ -75,7 +75,7 @@ class TestTaskOperations(APITestCase):
def setUp(self): def setUp(self):
self._stdout_handler = redirect_stdout(io.StringIO()) self._stdout_handler = redirect_stdout(io.StringIO())
mock_stdout = self._stdout_handler.__enter__() mock_stdout = self._stdout_handler.__enter__()
log = logging.getLogger("utils.cli") log = logging.getLogger("cvat_cli")
log.propagate = False log.propagate = False
log.setLevel(logging.INFO) log.setLevel(logging.INFO)
log.handlers.clear() log.handlers.clear()

@ -2,7 +2,7 @@
title: 'Command line interface (CLI)' title: 'Command line interface (CLI)'
linkTitle: 'CLI' linkTitle: 'CLI'
weight: 29 weight: 29
description: 'Guide to working with CVAT tasks in the command line interface. This section on [GitHub](https://github.com/openvinotoolkit/cvat/tree/develop/utils/cli).' description: 'Guide to working with CVAT tasks in the command line interface. This section on [GitHub](https://github.com/openvinotoolkit/cvat/tree/develop/cvat-cli).'
--- ---
## Description ## Description
@ -28,15 +28,13 @@ To access the CLI, you need to have python in environment,
as well as a clone of the CVAT repository and the necessary modules: as well as a clone of the CVAT repository and the necessary modules:
```bash ```bash
git clone https://github.com/openvinotoolkit/cvat.git pip install 'git+https://github.com/openvinotoolkit/cvat#subdirectory=cvat-cli'
cd cvat/utils/cli
pip install -r requirements.txt
``` ```
You will get help with `cli.py`. You can get help with `cvat-cli --help`.
``` ```
usage: cli.py [-h] [--auth USER:[PASS]] [--server-host SERVER_HOST] usage: cvat-cli [-h] [--auth USER:[PASS]] [--server-host SERVER_HOST]
[--server-port SERVER_PORT] [--debug] [--server-port SERVER_PORT] [--debug]
{create,delete,ls,frames,dump,upload,export,import} ... {create,delete,ls,frames,dump,upload,export,import} ...
@ -61,10 +59,10 @@ optional arguments:
You can get help for each positional argument, e.g. `ls`: You can get help for each positional argument, e.g. `ls`:
```bash ```bash
cli.py ls -h cvat-cli ls -h
``` ```
``` ```
usage: cli.py ls [-h] [--json] usage: cvat-cli ls [-h] [--json]
List all CVAT tasks in simple or JSON format. List all CVAT tasks in simple or JSON format.
@ -103,25 +101,25 @@ by using the [label constructor](/docs/manual/basics/creating_an_annotation_task
- Create a task named "new task" on the default server "localhost:8080", labels from the file "labels.json" - Create a task named "new task" on the default server "localhost:8080", labels from the file "labels.json"
and local images "file1.jpg" and "file2.jpg", the task will be created as current user: and local images "file1.jpg" and "file2.jpg", the task will be created as current user:
```bash ```bash
cli.py create "new task" --labels labels.json local file1.jpg file2.jpg cvat-cli create "new task" --labels labels.json local file1.jpg file2.jpg
``` ```
- Create a task named "task 1" on the server "example.com" labels from the file "labels.json" - Create a task named "task 1" on the server "example.com" labels from the file "labels.json"
and local image "image1.jpg", the task will be created as user "user-1": and local image "image1.jpg", the task will be created as user "user-1":
```bash ```bash
cli.py --server-host example.com --auth user-1 create "task 1" \ cvat-cli --server-host example.com --auth user-1 create "task 1" \
--labels labels.json local image1.jpg --labels labels.json local image1.jpg
``` ```
- Create a task named "task 1", labels from the project with id 1 and with a remote video file, - Create a task named "task 1", labels from the project with id 1 and with a remote video file,
the task will be created as user "user-1": the task will be created as user "user-1":
```bash ```bash
cli.py --auth user-1:password create "task 1" --project_id 1 \ cvat-cli --auth user-1:password create "task 1" --project_id 1 \
remote https://github.com/opencv/opencv/blob/master/samples/data/vtest.avi?raw=true remote https://github.com/opencv/opencv/blob/master/samples/data/vtest.avi?raw=true
``` ```
- Create a task named "task 1 sort random", with labels "cat" and "dog", with chunk size 8, - Create a task named "task 1 sort random", with labels "cat" and "dog", with chunk size 8,
with sorting-method random, frame step 10, copy the data on the CVAT server, with sorting-method random, frame step 10, copy the data on the CVAT server,
with use zip chunks and the video file will be taken from the shared resource: with use zip chunks and the video file will be taken from the shared resource:
```bash ```bash
cli.py create "task 1 sort random" --labels '[{"name": "cat"},{"name": "dog"}]' --chunk_size 8 \ cvat-cli create "task 1 sort random" --labels '[{"name": "cat"},{"name": "dog"}]' --chunk_size 8 \
--sorting-method random --frame_step 10 --copy_data --use_zip_chunks share //share/dataset_1/video.avi --sorting-method random --frame_step 10 --copy_data --use_zip_chunks share //share/dataset_1/video.avi
``` ```
- Create a task named "task from dataset_1", labels from the file "labels.json", with link to bug tracker, - Create a task named "task from dataset_1", labels from the file "labels.json", with link to bug tracker,
@ -129,21 +127,21 @@ by using the [label constructor](/docs/manual/basics/creating_an_annotation_task
from the file "annotation.xml", the data will be loaded from "dataset_1/images/", from the file "annotation.xml", the data will be loaded from "dataset_1/images/",
the task will be created as user "user-2", and the password will need to be entered additionally: the task will be created as user "user-2", and the password will need to be entered additionally:
```bash ```bash
cli.py --auth user-2 create "task from dataset_1" --labels labels.json \ cvat-cli --auth user-2 create "task from dataset_1" --labels labels.json \
--bug_tracker https://bug-tracker.com/0001 --image_quality 75 --annotation_path annotation.xml \ --bug_tracker https://bug-tracker.com/0001 --image_quality 75 --annotation_path annotation.xml \
--annotation_format "CVAT 1.1" local dataset_1/images/ --annotation_format "CVAT 1.1" local dataset_1/images/
``` ```
- Create a task named "segmented task 1", labels from the file "labels.json", with overlay size 5, - Create a task named "segmented task 1", labels from the file "labels.json", with overlay size 5,
segment size 100, with frames 5 through 705, using cache and with a remote video file: segment size 100, with frames 5 through 705, using cache and with a remote video file:
```bash ```bash
cli.py create "segmented task 1" --labels labels.json --overlap 5 --segment_size 100 \ cvat-cli create "segmented task 1" --labels labels.json --overlap 5 --segment_size 100 \
--start_frame 5 --stop_frame 705 --use_cache \ --start_frame 5 --stop_frame 705 --use_cache \
remote https://github.com/opencv/opencv/blob/master/samples/data/vtest.avi?raw=true remote https://github.com/opencv/opencv/blob/master/samples/data/vtest.avi?raw=true
``` ```
- Create a task named "task 1 with sync annotation", with label "person", - Create a task named "task 1 with sync annotation", with label "person",
with annotation storage in `git` repository, enable `lfs` and the image files from the shared resource: with annotation storage in `git` repository, enable `lfs` and the image files from the shared resource:
```bash ```bash
cli.py create "task 1 with sync annotation" --labels '[{"name": "person"}]' \ cvat-cli create "task 1 with sync annotation" --labels '[{"name": "person"}]' \
--dataset_repository_url https://github.com/user/dataset/blob/main/annotation/anno_file_name.zip \ --dataset_repository_url https://github.com/user/dataset/blob/main/annotation/anno_file_name.zip \
--lfs share //share/large_dataset/images/ --lfs share //share/large_dataset/images/
``` ```
@ -152,55 +150,55 @@ by using the [label constructor](/docs/manual/basics/creating_an_annotation_task
- Delete tasks with id "100", "101", "102" , the command will be executed from "user-1" having delete permissions: - Delete tasks with id "100", "101", "102" , the command will be executed from "user-1" having delete permissions:
```bash ```bash
cli.py --auth user-1:password delete 100 101 102 cvat-cli --auth user-1:password delete 100 101 102
``` ```
### List ### List
- List all tasks: - List all tasks:
```bash ```bash
cli.py ls cvat-cli ls
``` ```
- Save list of all tasks into file "list_of_tasks.json": - Save list of all tasks into file "list_of_tasks.json":
```bash ```bash
cli.py ls --json > list_of_tasks.json cvat-cli ls --json > list_of_tasks.json
``` ```
### Frames ### Frames
- Save frame 12, 15, 22 from task with id 119, into "images" folder with compressed quality: - Save frame 12, 15, 22 from task with id 119, into "images" folder with compressed quality:
```bash ```bash
cli.py frames --outdir images --quality compressed 119 12 15 22 cvat-cli frames --outdir images --quality compressed 119 12 15 22
``` ```
### Dump annotation ### Dump annotation
- Dump annotation task with id 103, in the format `CVAT for images 1.1` and save to the file "output.zip": - Dump annotation task with id 103, in the format `CVAT for images 1.1` and save to the file "output.zip":
```bash ```bash
cli.py dump --format "CVAT for images 1.1" 103 output.zip cvat-cli dump --format "CVAT for images 1.1" 103 output.zip
``` ```
- Dump annotation task with id 104, in the format `COCO 1.0` and save to the file "output.zip": - Dump annotation task with id 104, in the format `COCO 1.0` and save to the file "output.zip":
```bash ```bash
cli.py dump --format "COCO 1.0" 104 output.zip cvat-cli dump --format "COCO 1.0" 104 output.zip
``` ```
### Upload annotation ### Upload annotation
- Upload annotation into task with id 105, in the format `CVAT 1.1` from the file "annotation.xml": - Upload annotation into task with id 105, in the format `CVAT 1.1` from the file "annotation.xml":
```bash ```bash
cli.py upload --format "CVAT 1.1" 105 annotation.xml cvat-cli upload --format "CVAT 1.1" 105 annotation.xml
``` ```
### Export task ### Export task
- Export task with id 136 to file "task_136.zip": - Export task with id 136 to file "task_136.zip":
```bash ```bash
cli.py export 136 task_136.zip cvat-cli export 136 task_136.zip
``` ```
### Import ### Import
- Import task from file "task_backup.zip": - Import task from file "task_backup.zip":
```bash ```bash
cli.py import task_backup.zip cvat-cli import task_backup.zip
``` ```

@ -1,4 +0,0 @@
-r base.txt
# We depend on the server in tests
-r ../../../cvat/requirements/testing.txt
Loading…
Cancel
Save