Skip to content
This repository has been archived by the owner on Nov 14, 2023. It is now read-only.

Commit

Permalink
Migrate to using pathlib in most of the SDK (cvat-ai#5435)
Browse files Browse the repository at this point in the history
For user-facing functions, keep accepting `str` paths to maintain
compatibility and flexibility, but add support for arbitrary path-like
objects. For internal functions (in `downloading.py` and
`uploading.py`), don't bother and require `pathlib.Path`.

The only code that isn't converted is build-time code (e.g. `setup.py`)
and code that came from openapi-generator.
  • Loading branch information
SpecLad authored and mikhail-treskin committed Jul 1, 2023
1 parent 29668be commit 89cbda5
Showing 10 changed files with 111 additions and 77 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -29,6 +29,8 @@ from online detectors & interactors) (<https://github.com/opencv/cvat/pull/4543>
- Allowed trailing slashes in the SDK host address (<https://github.com/opencv/cvat/pull/5057>)
- Adjusted initial camera position, enabled 'Reset zoom' option for 3D canvas (<https://github.com/opencv/cvat/pull/5395>)
- Enabled authentication via email (<https://github.com/opencv/cvat/pull/5037>)
- In the SDK, functions taking paths as strings now also accept path-like objects
(<https://github.com/opencv/cvat/pull/5435>)

### Deprecated
- TDB
8 changes: 4 additions & 4 deletions cvat-sdk/cvat_sdk/core/downloading.py
Original file line number Diff line number Diff line change
@@ -5,8 +5,8 @@

from __future__ import annotations

import os.path as osp
from contextlib import closing
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, Optional

from cvat_sdk.api_client.api_client import Endpoint
@@ -28,7 +28,7 @@ def __init__(self, client: Client):
def download_file(
self,
url: str,
output_path: str,
output_path: Path,
*,
timeout: int = 60,
pbar: Optional[ProgressReporter] = None,
@@ -39,7 +39,7 @@ def download_file(

CHUNK_SIZE = 10 * 2**20

assert not osp.exists(output_path)
assert not output_path.exists()

response = self._client.api_client.rest_client.GET(
url,
@@ -70,7 +70,7 @@ def download_file(
def prepare_and_download_file_from_endpoint(
self,
endpoint: Endpoint,
filename: str,
filename: Path,
*,
url_params: Optional[Dict[str, Any]] = None,
query_params: Optional[Dict[str, Any]] = None,
25 changes: 17 additions & 8 deletions cvat-sdk/cvat_sdk/core/proxies/jobs.py
Original file line number Diff line number Diff line change
@@ -6,9 +6,8 @@

import io
import mimetypes
import os
import os.path as osp
from typing import List, Optional, Sequence
from pathlib import Path
from typing import TYPE_CHECKING, List, Optional, Sequence

from PIL import Image

@@ -26,6 +25,9 @@
)
from cvat_sdk.core.uploading import AnnotationUploader

if TYPE_CHECKING:
from _typeshed import StrPath

_JobEntityBase, _JobRepoBase = build_model_bases(
models.JobRead, apis.JobsApi, api_member_name="jobs_api"
)
@@ -43,7 +45,7 @@ class Job(
def import_annotations(
self,
format_name: str,
filename: str,
filename: StrPath,
*,
status_check_period: Optional[int] = None,
pbar: Optional[ProgressReporter] = None,
@@ -52,6 +54,8 @@ def import_annotations(
Upload annotations for a job in the specified format (e.g. 'YOLO ZIP 1.0').
"""

filename = Path(filename)

AnnotationUploader(self._client).upload_file_and_wait(
self.api.create_annotations_endpoint,
filename,
@@ -66,7 +70,7 @@ def import_annotations(
def export_dataset(
self,
format_name: str,
filename: str,
filename: StrPath,
*,
pbar: Optional[ProgressReporter] = None,
status_check_period: Optional[int] = None,
@@ -75,6 +79,9 @@ def export_dataset(
"""
Download annotations for a job in the specified format (e.g. 'YOLO ZIP 1.0').
"""

filename = Path(filename)

if include_images:
endpoint = self.api.retrieve_dataset_endpoint
else:
@@ -112,15 +119,17 @@ def download_frames(
self,
frame_ids: Sequence[int],
*,
outdir: str = "",
outdir: StrPath = ".",
quality: str = "original",
filename_pattern: str = "frame_{frame_id:06d}{frame_ext}",
) -> Optional[List[Image.Image]]:
"""
Download the requested frame numbers for a job and save images as outdir/filename_pattern
"""
# TODO: add arg descriptions in schema
os.makedirs(outdir, exist_ok=True)

outdir = Path(outdir)
outdir.mkdir(parents=True, exist_ok=True)

for frame_id in frame_ids:
frame_bytes = self.get_frame(frame_id, quality=quality)
@@ -136,7 +145,7 @@ def download_frames(
im_ext = ".jpg"

outfile = filename_pattern.format(frame_id=frame_id, frame_ext=im_ext)
im.save(osp.join(outdir, outfile))
im.save(outdir / outfile)

def get_meta(self) -> models.IDataMetaRead:
(meta, _) = self.api.retrieve_data_meta(self.id)
27 changes: 20 additions & 7 deletions cvat-sdk/cvat_sdk/core/proxies/projects.py
Original file line number Diff line number Diff line change
@@ -5,8 +5,8 @@
from __future__ import annotations

import json
import os.path as osp
from typing import Optional
from pathlib import Path
from typing import TYPE_CHECKING, Optional

from cvat_sdk.api_client import apis, models
from cvat_sdk.core.downloading import Downloader
@@ -21,6 +21,9 @@
)
from cvat_sdk.core.uploading import DatasetUploader, Uploader

if TYPE_CHECKING:
from _typeshed import StrPath

_ProjectEntityBase, _ProjectRepoBase = build_model_bases(
models.ProjectRead, apis.ProjectsApi, api_member_name="projects_api"
)
@@ -34,7 +37,7 @@ class Project(
def import_dataset(
self,
format_name: str,
filename: str,
filename: StrPath,
*,
status_check_period: Optional[int] = None,
pbar: Optional[ProgressReporter] = None,
@@ -43,6 +46,8 @@ def import_dataset(
Import dataset for a project in the specified format (e.g. 'YOLO ZIP 1.0').
"""

filename = Path(filename)

DatasetUploader(self._client).upload_file_and_wait(
self.api.create_dataset_endpoint,
filename,
@@ -57,7 +62,7 @@ def import_dataset(
def export_dataset(
self,
format_name: str,
filename: str,
filename: StrPath,
*,
pbar: Optional[ProgressReporter] = None,
status_check_period: Optional[int] = None,
@@ -66,6 +71,9 @@ def export_dataset(
"""
Download annotations for a project in the specified format (e.g. 'YOLO ZIP 1.0').
"""

filename = Path(filename)

if include_images:
endpoint = self.api.retrieve_dataset_endpoint
else:
@@ -84,7 +92,7 @@ def export_dataset(

def download_backup(
self,
filename: str,
filename: StrPath,
*,
status_check_period: int = None,
pbar: Optional[ProgressReporter] = None,
@@ -93,6 +101,8 @@ def download_backup(
Download a project backup
"""

filename = Path(filename)

Downloader(self._client).prepare_and_download_file_from_endpoint(
self.api.retrieve_backup_endpoint,
filename=filename,
@@ -148,18 +158,21 @@ def create_from_dataset(

def create_from_backup(
self,
filename: str,
filename: StrPath,
*,
status_check_period: int = None,
pbar: Optional[ProgressReporter] = None,
) -> Project:
"""
Import a project from a backup file
"""

filename = Path(filename)

if status_check_period is None:
status_check_period = self.config.status_check_period

params = {"filename": osp.basename(filename)}
params = {"filename": filename.name}
url = self.api_map.make_endpoint_url(self.api.create_backup_endpoint.path)

uploader = Uploader(self)
Loading

0 comments on commit 89cbda5

Please sign in to comment.