Skip to content

Commit 29912ad

Browse files
committed
Update download annotations
1 parent 08b286a commit 29912ad

File tree

12 files changed

+115
-96
lines changed

12 files changed

+115
-96
lines changed

src/superannotate/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from packaging.version import parse # noqa
99
from superannotate.lib.app.analytics.class_analytics import class_distribution # noqa
1010
from superannotate.lib.app.exceptions import AppException # noqa
11-
from superannotate.lib.app.input_converters import convert_json_version
11+
from superannotate.lib.app.input_converters import convert_json_version # noqa
1212
from superannotate.lib.app.input_converters import convert_project_type # noqa
1313
from superannotate.lib.app.input_converters import export_annotation # noqa
1414
from superannotate.lib.app.input_converters import import_annotation # noqa
@@ -18,7 +18,7 @@
1818
from superannotate.lib.core import PACKAGE_VERSION_UPGRADE # noqa
1919
from superannotate.logger import get_default_logger # noqa
2020
from superannotate.version import __version__ # noqa
21-
import superannotate.lib.core.enums as enums
21+
import superannotate.lib.core.enums as enums # noqa
2222

2323

2424
SESSIONS = {}

src/superannotate/lib/app/interface/base_interface.py

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from types import FunctionType
88
from typing import Iterable
99
from typing import Sized
10+
from typing import Tuple
1011

1112
import lib.core as constants
1213
from lib.app.helpers import extract_project_folder
@@ -22,44 +23,45 @@
2223
class BaseInterfaceFacade:
2324
REGISTRY = []
2425

25-
def __init__(
26-
self,
27-
token: str = None,
28-
config_path: str = constants.CONFIG_PATH,
29-
):
30-
host = constants.BACKEND_URL
31-
env_token = os.environ.get("SA_TOKEN")
26+
def __init__(self, token: str = None, config_path: str = None):
3227
version = os.environ.get("SA_VERSION", "v1")
33-
ssl_verify = bool(os.environ.get("SA_SSL", True))
28+
_token, _config_path = None, None
29+
_host = os.environ.get("SA_URL", constants.BACKEND_URL)
30+
_ssl_verify = bool(os.environ.get("SA_SSL", True))
3431
if token:
35-
token = Controller.validate_token(token=token)
36-
elif env_token:
37-
host = os.environ.get("SA_URL", constants.BACKEND_URL)
38-
39-
token = Controller.validate_token(env_token)
32+
_token = Controller.validate_token(token=token)
33+
elif config_path:
34+
_token, _host, _ssl_verify = self._retrieve_configs(config_path)
4035
else:
41-
config_path = os.path.expanduser(str(config_path))
42-
if not Path(config_path).is_file() or not os.access(config_path, os.R_OK):
43-
raise AppException(
44-
f"SuperAnnotate config file {str(config_path)} not found."
45-
f" Please provide correct config file location to sa.init(<path>) or use "
46-
f"CLI's superannotate init to generate default location config file."
36+
_token = os.environ.get("SA_TOKEN")
37+
if not _token:
38+
_toke, _host, _ssl_verify = self._retrieve_configs(
39+
constants.CONFIG_PATH
4740
)
48-
config_repo = ConfigRepository(config_path)
49-
token, host, ssl_verify = (
50-
Controller.validate_token(config_repo.get_one("token").value),
51-
config_repo.get_one("main_endpoint").value,
52-
config_repo.get_one("ssl_verify").value,
53-
)
54-
self._host = host
55-
self._token = token
56-
self.controller = Controller(token, host, ssl_verify, version)
41+
self._token, self._host = _host, _token
42+
self.controller = Controller(_token, _host, _ssl_verify, version)
5743

5844
def __new__(cls, *args, **kwargs):
5945
obj = super().__new__(cls, *args, **kwargs)
6046
cls.REGISTRY.append(obj)
6147
return obj
6248

49+
@staticmethod
50+
def _retrieve_configs(path) -> Tuple[str, str, str]:
51+
config_path = os.path.expanduser(str(path))
52+
if not Path(config_path).is_file() or not os.access(config_path, os.R_OK):
53+
raise AppException(
54+
f"SuperAnnotate config file {str(config_path)} not found."
55+
f" Please provide correct config file location to sa.init(<path>) or use "
56+
f"CLI's superannotate init to generate default location config file."
57+
)
58+
config_repo = ConfigRepository(config_path)
59+
return (
60+
Controller.validate_token(config_repo.get_one("token").value),
61+
config_repo.get_one("main_endpoint").value,
62+
config_repo.get_one("ssl_verify").value,
63+
)
64+
6365
@property
6466
@abstractmethod
6567
def host(self):

src/superannotate/lib/app/interface/sdk_interface.py

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from typing import Union
1414

1515
import boto3
16-
import lib.core as constances
16+
import lib.core as constants
1717
from lib.app.annotation_helpers import add_annotation_bbox_to_json
1818
from lib.app.annotation_helpers import add_annotation_comment_to_json
1919
from lib.app.annotation_helpers import add_annotation_point_to_json
@@ -62,6 +62,13 @@
6262

6363

6464
class SAClient(BaseInterfaceFacade, metaclass=TrackableMeta):
65+
def __init__(
66+
self,
67+
token: str = None,
68+
config_path: str = constants.CONFIG_PATH,
69+
):
70+
super().__init__(token, config_path)
71+
6572
def get_team_metadata(self):
6673
"""Returns team metadata
6774
@@ -415,11 +422,11 @@ def copy_image(
415422
).data
416423

417424
if destination_project_metadata["project"].type in [
418-
constances.ProjectType.VIDEO.value,
419-
constances.ProjectType.DOCUMENT.value,
425+
constants.ProjectType.VIDEO.value,
426+
constants.ProjectType.DOCUMENT.value,
420427
] or source_project_metadata["project"].type in [
421-
constances.ProjectType.VIDEO.value,
422-
constances.ProjectType.DOCUMENT.value,
428+
constants.ProjectType.VIDEO.value,
429+
constants.ProjectType.DOCUMENT.value,
423430
]:
424431
raise AppException(
425432
LIMITED_FUNCTIONS[source_project_metadata["project"].type]
@@ -685,8 +692,8 @@ def assign_images(
685692
project = self.controller.get_project_metadata(project_name).data
686693

687694
if project["project"].type in [
688-
constances.ProjectType.VIDEO.value,
689-
constances.ProjectType.DOCUMENT.value,
695+
constants.ProjectType.VIDEO.value,
696+
constants.ProjectType.DOCUMENT.value,
690697
]:
691698
raise AppException(LIMITED_FUNCTIONS[project["project"].type])
692699

@@ -803,12 +810,12 @@ def upload_images_from_folder_to_project(
803810
folder_path: Union[NotEmptyStr, Path],
804811
extensions: Optional[
805812
Union[List[NotEmptyStr], Tuple[NotEmptyStr]]
806-
] = constances.DEFAULT_IMAGE_EXTENSIONS,
813+
] = constants.DEFAULT_IMAGE_EXTENSIONS,
807814
annotation_status="NotStarted",
808815
from_s3_bucket=None,
809816
exclude_file_patterns: Optional[
810817
Iterable[NotEmptyStr]
811-
] = constances.DEFAULT_FILE_EXCLUDE_PATTERNS,
818+
] = constants.DEFAULT_FILE_EXCLUDE_PATTERNS,
812819
recursive_subfolders: Optional[StrictBool] = False,
813820
image_quality_in_editor: Optional[str] = None,
814821
):
@@ -865,7 +872,7 @@ def upload_images_from_folder_to_project(
865872

866873
if exclude_file_patterns:
867874
exclude_file_patterns = list(exclude_file_patterns) + list(
868-
constances.DEFAULT_FILE_EXCLUDE_PATTERNS
875+
constants.DEFAULT_FILE_EXCLUDE_PATTERNS
869876
)
870877
exclude_file_patterns = list(set(exclude_file_patterns))
871878

@@ -1021,12 +1028,12 @@ def prepare_export(
10211028
folders = folder_names
10221029
if not annotation_statuses:
10231030
annotation_statuses = [
1024-
constances.AnnotationStatus.NOT_STARTED.name,
1025-
constances.AnnotationStatus.IN_PROGRESS.name,
1026-
constances.AnnotationStatus.QUALITY_CHECK.name,
1027-
constances.AnnotationStatus.RETURNED.name,
1028-
constances.AnnotationStatus.COMPLETED.name,
1029-
constances.AnnotationStatus.SKIPPED.name,
1031+
constants.AnnotationStatus.NOT_STARTED.name,
1032+
constants.AnnotationStatus.IN_PROGRESS.name,
1033+
constants.AnnotationStatus.QUALITY_CHECK.name,
1034+
constants.AnnotationStatus.RETURNED.name,
1035+
constants.AnnotationStatus.COMPLETED.name,
1036+
constants.AnnotationStatus.SKIPPED.name,
10301037
]
10311038
response = self.controller.prepare_export(
10321039
project_name=project_name,
@@ -1045,7 +1052,7 @@ def upload_videos_from_folder_to_project(
10451052
folder_path: Union[NotEmptyStr, Path],
10461053
extensions: Optional[
10471054
Union[Tuple[NotEmptyStr], List[NotEmptyStr]]
1048-
] = constances.DEFAULT_VIDEO_EXTENSIONS,
1055+
] = constants.DEFAULT_VIDEO_EXTENSIONS,
10491056
exclude_file_patterns: Optional[List[NotEmptyStr]] = (),
10501057
recursive_subfolders: Optional[StrictBool] = False,
10511058
target_fps: Optional[int] = None,
@@ -1532,8 +1539,8 @@ def upload_preannotations_from_folder_to_project(
15321539
project_folder_name = project_name + (f"/{folder_name}" if folder_name else "")
15331540
project = self.controller.get_project_metadata(project_name).data
15341541
if project["project"].type in [
1535-
constances.ProjectType.VIDEO.value,
1536-
constances.ProjectType.DOCUMENT.value,
1542+
constants.ProjectType.VIDEO.value,
1543+
constants.ProjectType.DOCUMENT.value,
15371544
]:
15381545
raise AppException(LIMITED_FUNCTIONS[project["project"].type])
15391546
if recursive_subfolders:
@@ -1588,8 +1595,8 @@ def upload_image_annotations(
15881595

15891596
project = self.controller.get_project_metadata(project_name).data
15901597
if project["project"].type in [
1591-
constances.ProjectType.VIDEO.value,
1592-
constances.ProjectType.DOCUMENT.value,
1598+
constants.ProjectType.VIDEO.value,
1599+
constants.ProjectType.DOCUMENT.value,
15931600
]:
15941601
raise AppException(LIMITED_FUNCTIONS[project["project"].type])
15951602

@@ -1616,7 +1623,7 @@ def upload_image_annotations(
16161623
mask=mask,
16171624
verbose=verbose,
16181625
)
1619-
if response.errors and not response.errors == constances.INVALID_JSON_MESSAGE:
1626+
if response.errors and not response.errors == constants.INVALID_JSON_MESSAGE:
16201627
raise AppException(response.errors)
16211628

16221629
def download_model(self, model: MLModel, output_dir: Union[str, Path]):
@@ -1674,8 +1681,8 @@ def benchmark(
16741681

16751682
project = self.controller.get_project_metadata(project_name).data
16761683
if project["project"].type in [
1677-
constances.ProjectType.VIDEO.value,
1678-
constances.ProjectType.DOCUMENT.value,
1684+
constants.ProjectType.VIDEO.value,
1685+
constants.ProjectType.DOCUMENT.value,
16791686
]:
16801687
raise AppException(LIMITED_FUNCTIONS[project["project"].type])
16811688

@@ -1826,8 +1833,8 @@ def add_annotation_bbox_to_image(
18261833
project_name, folder_name = extract_project_folder(project)
18271834
project = self.controller.get_project_metadata(project_name).data
18281835
if project["project"].type in [
1829-
constances.ProjectType.VIDEO.value,
1830-
constances.ProjectType.DOCUMENT.value,
1836+
constants.ProjectType.VIDEO.value,
1837+
constants.ProjectType.DOCUMENT.value,
18311838
]:
18321839
raise AppException(LIMITED_FUNCTIONS[project["project"].type])
18331840
response = self.controller.get_annotations(
@@ -1884,8 +1891,8 @@ def add_annotation_point_to_image(
18841891
project_name, folder_name = extract_project_folder(project)
18851892
project = self.controller.get_project_metadata(project_name).data
18861893
if project["project"].type in [
1887-
constances.ProjectType.VIDEO.value,
1888-
constances.ProjectType.DOCUMENT.value,
1894+
constants.ProjectType.VIDEO.value,
1895+
constants.ProjectType.DOCUMENT.value,
18891896
]:
18901897
raise AppException(LIMITED_FUNCTIONS[project["project"].type])
18911898
response = self.controller.get_annotations(
@@ -1939,8 +1946,8 @@ def add_annotation_comment_to_image(
19391946
project_name, folder_name = extract_project_folder(project)
19401947
project = self.controller.get_project_metadata(project_name).data
19411948
if project["project"].type in [
1942-
constances.ProjectType.VIDEO.value,
1943-
constances.ProjectType.DOCUMENT.value,
1949+
constants.ProjectType.VIDEO.value,
1950+
constants.ProjectType.DOCUMENT.value,
19441951
]:
19451952
raise AppException(LIMITED_FUNCTIONS[project["project"].type])
19461953
response = self.controller.get_annotations(
@@ -2126,8 +2133,8 @@ def aggregate_annotations_as_df(
21262133
:rtype: pandas DataFrame
21272134
"""
21282135
if project_type in (
2129-
constances.ProjectType.VECTOR.name,
2130-
constances.ProjectType.PIXEL.name,
2136+
constants.ProjectType.VECTOR.name,
2137+
constants.ProjectType.PIXEL.name,
21312138
):
21322139
from superannotate.lib.app.analytics.common import (
21332140
aggregate_image_annotations_as_df,
@@ -2141,8 +2148,8 @@ def aggregate_annotations_as_df(
21412148
folder_names=folder_names,
21422149
)
21432150
elif project_type in (
2144-
constances.ProjectType.VIDEO.name,
2145-
constances.ProjectType.DOCUMENT.name,
2151+
constants.ProjectType.VIDEO.name,
2152+
constants.ProjectType.DOCUMENT.name,
21462153
):
21472154
from superannotate.lib.app.analytics.aggregators import DataAggregator
21482155

@@ -2153,21 +2160,21 @@ def aggregate_annotations_as_df(
21532160
).aggregate_annotations_as_df()
21542161

21552162
def delete_annotations(
2156-
self, project: NotEmptyStr, image_names: Optional[List[NotEmptyStr]] = None
2163+
self, project: NotEmptyStr, item_names: Optional[List[NotEmptyStr]] = None
21572164
):
21582165
"""
2159-
Delete image annotations from a given list of images.
2166+
Delete item annotations from a given list of items.
21602167
21612168
:param project: project name or folder path (e.g., "project1/folder1")
21622169
:type project: str
2163-
:param image_names: image names. If None, all image annotations from a given project/folder will be deleted.
2164-
:type image_names: list of strs
2170+
:param item_names: image names. If None, all image annotations from a given project/folder will be deleted.
2171+
:type item_names: list of strs
21652172
"""
21662173

21672174
project_name, folder_name = extract_project_folder(project)
21682175

21692176
response = self.controller.delete_annotations(
2170-
project_name=project_name, folder_name=folder_name, item_names=image_names
2177+
project_name=project_name, folder_name=folder_name, item_names=item_names
21712178
)
21722179
if response.errors:
21732180
raise AppException(response.errors)

src/superannotate/lib/app/interface/types.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,26 @@
1414
from pydantic import BaseModel
1515
from pydantic import conlist
1616
from pydantic import constr
17+
from pydantic import errors
1718
from pydantic import Extra
1819
from pydantic import Field
1920
from pydantic import parse_obj_as
2021
from pydantic import root_validator
2122
from pydantic import StrictStr
2223
from pydantic import validate_arguments as pydantic_validate_arguments
2324
from pydantic import ValidationError
24-
from pydantic.errors import StrRegexError
25-
from pydantic import errors
2625
from pydantic.errors import PydanticTypeError
26+
from pydantic.errors import StrRegexError
2727

2828
NotEmptyStr = constr(strict=True, min_length=1)
2929

3030

3131
class EnumMemberError(PydanticTypeError):
32-
code = 'enum'
32+
code = "enum"
3333

3434
def __str__(self) -> str:
35-
permitted = ', '.join(str(v.name) for v in self.enum_values) # type: ignore
36-
return f'Available values are: {permitted}'
35+
permitted = ", ".join(str(v.name) for v in self.enum_values) # type: ignore
36+
return f"Available values are: {permitted}"
3737

3838

3939
errors.EnumMemberError = EnumMemberError

src/superannotate/lib/core/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from os.path import expanduser
2-
from pathlib import Path
32

43
from superannotate.lib.core.enums import AnnotationStatus
54
from superannotate.lib.core.enums import ImageQuality

src/superannotate/lib/core/enums.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def equals(self, other: Enum):
4747
return self.__doc__.lower() == other.__doc__.lower()
4848

4949
def __eq__(self, other):
50-
return super(BaseTitledEnum, self).__eq__(other)
50+
return super().__eq__(other)
5151

5252

5353
class AnnotationTypes(str, Enum):

src/superannotate/lib/core/serviceproviders.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,10 @@ async def download_annotations(
318318
postfix: str,
319319
items: List[str] = None,
320320
callback: Callable = None,
321-
) -> List[dict]:
321+
) -> int:
322+
"""
323+
Returns the number of items downloaded
324+
"""
322325
raise NotImplementedError
323326

324327
def upload_priority_scores(

0 commit comments

Comments
 (0)