Extend SDK layer 2 docs (#4980)

main
Maxim Zhiltsov 3 years ago committed by GitHub
parent 426f8e3ef0
commit 1902ecd8a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -30,6 +30,10 @@ from cvat_sdk.version import VERSION
@attrs.define
class Config:
"""
Allows to tweak behavior of Client instances.
"""
status_check_period: float = 5
"""Operation status check period, in seconds"""
@ -42,7 +46,8 @@ class Config:
class Client:
"""
Manages session and configuration.
Provides session management, implements authentication operations
and simplifies access to server APIs.
"""
SUPPORTED_SERVER_VERSIONS = (
@ -61,17 +66,26 @@ class Client:
check_server_version: bool = True,
) -> None:
url = self._validate_and_prepare_url(url)
self.logger = logger or logging.getLogger(__name__)
"""The root logger"""
self.config = config or Config()
"""Configuration for this object"""
self.api_map = CVAT_API_V2(url)
"""Handles server API URL interaction logic"""
self.api_client = ApiClient(
Configuration(host=self.api_map.host, verify_ssl=self.config.verify_ssl)
)
"""Provides low-level access to the CVAT server"""
if check_server_version:
self.check_server_version()
self._repos: Dict[str, Repo] = {}
"""A cache for created Repository instances"""
ALLOWED_SCHEMAS = ("https", "http")

@ -55,7 +55,8 @@ class ModelProxy(ABC, Generic[ModelType, ApiType]):
class Entity(ModelProxy[ModelType, ApiType]):
"""
Represents a single object. Implements related operations and provides access to data members.
Represents a single object. Implements related operations and provides read access
to data members.
"""
_model: ModelType
@ -121,7 +122,7 @@ _EntityT = TypeVar("_EntityT", bound=Entity)
class ModelCreateMixin(Generic[_EntityT, IModel]):
def create(self: Repo, spec: Union[Dict[str, Any], IModel]) -> _EntityT:
"""
Creates a new object on the server and returns corresponding local object
Creates a new object on the server and returns the corresponding local object
"""
(model, _) = self.api.create(spec)
@ -131,7 +132,7 @@ class ModelCreateMixin(Generic[_EntityT, IModel]):
class ModelRetrieveMixin(Generic[_EntityT]):
def retrieve(self: Repo, obj_id: int) -> _EntityT:
"""
Retrieves an object from server by ID
Retrieves an object from the server by ID
"""
(model, _) = self.api.retrieve(id=obj_id)
@ -181,7 +182,7 @@ class ModelUpdateMixin(ABC, Generic[IModel]):
def fetch(self: Entity) -> Self:
"""
Updates current object from the server
Updates the current object from the server
"""
# TODO: implement revision checking
@ -190,7 +191,9 @@ class ModelUpdateMixin(ABC, Generic[IModel]):
def update(self: Entity, values: Union[Dict[str, Any], IModel]) -> Self:
"""
Commits local model changes to the server
Commits model changes to the server
The local object is updated from the server after this operation.
"""
# TODO: implement revision checking

@ -1,5 +1,5 @@
---
title: 'Python SDK'
title: 'CVAT Python SDK'
linkTitle: 'SDK'
weight: 3
description: ''
@ -7,17 +7,18 @@ description: ''
## Overview
SDK is a Python library. It provides you access to Python function and objects, which
simplify server interaction and provide additional functionality like data validation.
CVAT SDK is a Python library. It provides you access to Python functions and objects that
simplify server interaction and provide additional functionality like data validation
and serialization.
SDK API includes 2 layers:
- Low-level API with REST API wrappers. Located in at `cvat_sdk.api_client`. [Read more](../sdk/lowlevel-api)
- High-level API. Located at `cvat_sdk.core`. [Read more](../sdk/highlevel-api)
- Low-level API with REST API wrappers. Located at `cvat_sdk.api_client`. [Read more](/docs/api_sdk/sdk/lowlevel-api)
- High-level API. Located at `cvat_sdk.core`. [Read more](/docs/api_sdk/sdk/highlevel-api)
Roughly, low-level API provides single-request operations, while the high-level one allows you
to use composite, multi-request operations and have local counterparts for server objects.
For most uses, the high-level API should be good enough and sufficient, and it should be
right point to start your integration with CVAT.
In general, the low-level API provides single-request operations, while the high-level one
implements composite, multi-request operations, and provides local proxies for server objects.
For most uses, the high-level API should be good enough, and it should be
the right point to start your integration with CVAT.
## Installation
@ -30,9 +31,9 @@ We support Python versions 3.7 - 3.9.
## Usage
To import the package components, use the following code:
To import package components, use the following code:
For high-level API:
For the high-level API:
```python
import cvat_sdk
@ -40,7 +41,7 @@ import cvat_sdk
import cvat_sdk.core
```
For low-level API:
For the low-level API:
```python
import cvat_sdk.api_client

@ -9,10 +9,13 @@ description: ''
This layer provides high-level APIs, allowing easier access to server operations.
API includes _Repositories_ and _Entities_. Repositories provide management
operations for Entitites. Entitites represent separate objects on the server
(e.g. tasks, jobs etc).
operations for Entities. Entities represent objects on the server
(e.g. projects, tasks, jobs etc) and simplify interaction with them. The key difference
from the low-level API is that operations on this layer are not limited by a single
server request per operation and encapsulate low-level request machinery behind a high-level
object-oriented API.
Code of this component is located in `cvat_sdk.core`.
The code of this component is located in the `cvat_sdk.core` package.
## Example
@ -20,13 +23,14 @@ Code of this component is located in `cvat_sdk.core`.
from cvat_sdk import make_client, models
from cvat_sdk.core.proxies.tasks import ResourceType, Task
with make_client(host="http://localhost") as client:
# Authorize using the basic auth
client.login(('YOUR_USERNAME', 'YOUR_PASSWORD'))
# Create a Client instance bound to a local server and authenticate using basic auth
with make_client(host="localhost", credentials=('user', 'password')) as client:
# Let's create a new task.
# Models are used the same way as in the layer 1
# Fill in task parameters first.
# Models are used the same way as in the layer 1.
task_spec = {
"name": "example task 2",
"name": "example task",
"labels": [
{
"name": "car",
@ -44,20 +48,174 @@ with make_client(host="http://localhost") as client:
],
}
# Different repositories can be accessed as the Client class members.
# They may provide both simple and complex operations,
# such as entity creation, retrieval and removal.
# Now we can create a task using a task repository method.
# Repositories can be accessed as the Client class members.
# In this case we use 2 local images as the task data.
task = client.tasks.create_from_data(
spec=task_spec,
resource_type=ResourceType.LOCAL,
resources=['image1.jpg', 'image2.png'],
)
# Task object is already up-to-date with its server counterpart
# The returned task object is already up-to-date with its server counterpart.
# Now we can access task fields. The fields are read-only and can be optional.
# Let's check that we have 2 images in the task data.
assert task.size == 2
# An entity needs to be fetch()-ed to reflect the latest changes.
# It can be update()-d and remove()-d depending on the entity type.
task.update({'name': 'mytask'})
task.remove()
# If an object is modified on the server, the local object is not updated automatically.
# To reflect the latest changes, the local object needs to be fetch()-ed.
task.fetch()
# Let's obtain another task. Again, it can be done via the task repository.
# Suppose we have already created the task earlier and know the task id.
task2 = client.tasks.retrieve(42)
# The task object fields can be update()-d. Note that the set of fields that can be
# modified can be different from what is available for reading.
task2.update({'name': 'my task'})
# And the task can also be remove()-d from the server. The local copy will remain
# untouched.
task2.remove()
```
## Client
The `cvat_sdk.core.client.Client` class provides session management, implements
authentication operations and simplifies access to server APIs.
It is the starting point for using CVAT SDK.
A `Client` instance allows you to:
- configure connection options with the `Config` class
- check server API compatibility with the current SDK version
- deduce server connection scheme (`https` or `http`) automatically
- manage user session with the `login()`, `logout()` and other methods
- obtain Repository objects with the `users`, `tasks`, `jobs` and other members
- reach to lower-level APIs with the corresponding members
An instance of `Client` can be created directly by calling the class constructor
or with the utility function `cvat_sdk.core.client.make_client()` which can handle
some configuration for you. A `Client` can be configured with
the `cvat_sdk.core.client.Config` class instance. A `Config` object can be passed to
the `Client` constructor and then it will be available in the `Client.config` field.
The `Client` class implements the [context manager protocol](https://docs.python.org/3/reference/datamodel.html#context-managers).
When the context is closed, the session is finished, and the user is logged out
automatically. Otherwise, these actions can be done with the `close()` and `logout()` methods.
You can create and start using a `Client` instance this way:
```python
from cvat_sdk import make_client
with make_client('localhost', port='8080', credentials=('user', 'password')) as client:
...
```
The `make_client()` function handles configuration and object creation for you.
It also allows to authenticate right after the object is created.
If you need to configure `Client` parameters, you can do this:
```python
from cvat_sdk import Config, Client
config = Config()
# set up some config fields ...
with Client('localhost:8080', config=config) as client:
client.login(('user', 'password'))
...
```
You can specify server address both with and without the scheme. If the scheme is omitted,
it will be deduced automatically.
> The checks are performed in the following
order: `https` (with the default port 8080), `http` (with the default port 80).
In some cases it may lead to incorrect results - e.g. you have 2 servers running on the
same host at default ports. In such cases just specify the schema manually: `https://localhost`.
When the server is located, its version is checked. If an unsupported version is found,
an error can be raised or suppressed (controlled by `config.allow_unsupported_server`).
If the error is suppressed, some SDK functions may not work as expected with this server.
By default, a warning is raised and the error is suppressed.
> Please note that all `Client` operations rely on the server API and depend on the current user
rights. This affects the set of available APIs, objects and actions. For example, a regular user
can only see and modify their tasks and jobs, while an admin user can see all the tasks etc.
## Entities and Repositories
_Entities_ represent objects on the server. They provide read access to object fields
and implement additional relevant operations, including both the general Read-Update-Delete and
object-specific ones. The set of available general operations depends on the object type.
_Repositories_ provide management operations for corresponding Entities. You don't
need to create Repository objects manually. To obtain a Repository object, use the
corresponding `Client` instance member:
```python
client.projects
client.tasks
client.jobs
client.users
...
```
An Entity can be created on the server with the corresponding Repository method `create()`:
```python
task = client.tasks.create(<task config>)
```
We can retrieve server objects using the `retrieve()` and `list()` methods of the Repository:
```python
job = client.jobs.retrieve(<job id>)
tasks = client.tasks.list()
```
After calling these functions, we obtain local objects representing their server counterparts.
Object fields can be updated with the `update()` method. Note that the set of fields that can be
modified can be different from what is available for reading.
```python
job.update({'stage': 'validation'})
```
The server object will be updated and the local object will reflect the latest object state
after calling this operation.
Note that local objects may fall out of sync with their server counterparts for different reasons.
If you need to update the local object with the latest server state, use the `fetch()` method:
```python
# obtain 2 local copies of the same job
job_ref1 = client.jobs.retrieve(1)
job_ref2 = client.jobs.retrieve(1)
# update the server object with the first reference
job_ref1.update(...)
# job_ref2 is outdated now
job_ref2.fetch()
# job_ref2 is synced
```
Finally, if you need to remove the object from the server, you can use the `remove()` method.
The server object will be removed, but the local copy of the object will remain untouched.
```python
task = client.tasks.retrieve(<task id>)
task.remove()
```
Repositories can also provide group operations over entities. For instance, you can retrieve
all available objects using the `list()` Repository method. The list of available
Entity and Repository operations depends on the object type.
You can learn more about entity members and how model parameters are passed to functions [here](../lowlevel-api).
The implementation for these components is located in `cvat_sdk.core.proxies`.

Loading…
Cancel
Save