Skip to content

Commit 25e1421

Browse files
authored
Merge branch 'friday' into 1100_enums
2 parents 29912ad + 065b60e commit 25e1421

File tree

15 files changed

+350
-198
lines changed

15 files changed

+350
-198
lines changed

src/superannotate/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import logging.config # noqa
77
import requests # noqa
88
from packaging.version import parse # noqa
9+
from superannotate.lib.app.input_converters import convert_json_version # noqa
10+
from superannotate.lib.app.input_converters import convert_project_type # noqa
911
from superannotate.lib.app.analytics.class_analytics import class_distribution # noqa
1012
from superannotate.lib.app.exceptions import AppException # noqa
1113
from superannotate.lib.app.input_converters import convert_json_version # noqa
@@ -20,7 +22,6 @@
2022
from superannotate.version import __version__ # noqa
2123
import superannotate.lib.core.enums as enums # noqa
2224

23-
2425
SESSIONS = {}
2526

2627
__all__ = [

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

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import functools
22
import os
33
import sys
4-
from abc import abstractmethod
54
from inspect import signature
65
from pathlib import Path
76
from types import FunctionType
@@ -12,8 +11,8 @@
1211
import lib.core as constants
1312
from lib.app.helpers import extract_project_folder
1413
from lib.app.interface.types import validate_arguments
14+
from lib.core import CONFIG
1515
from lib.core.exceptions import AppException
16-
from lib.core.reporter import Session
1716
from lib.infrastructure.controller import Controller
1817
from lib.infrastructure.repositories import ConfigRepository
1918
from mixpanel import Mixpanel
@@ -63,19 +62,12 @@ def _retrieve_configs(path) -> Tuple[str, str, str]:
6362
)
6463

6564
@property
66-
@abstractmethod
6765
def host(self):
68-
raise NotImplementedError
66+
return self._host
6967

7068
@property
71-
@abstractmethod
7269
def token(self):
73-
raise NotImplementedError
74-
75-
@property
76-
@abstractmethod
77-
def logger(self):
78-
raise NotImplementedError
70+
return self._token
7971

8072

8173
class Tracker:
@@ -158,7 +150,7 @@ def _track_method(self, args, kwargs, success: bool):
158150
self._track(
159151
user_id,
160152
event_name,
161-
{**default, **properties, **Session.get_current_session().data},
153+
{**default, **properties, **CONFIG.get_current_session().data},
162154
)
163155

164156
def __get__(self, obj, owner=None):

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

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,51 @@ def delete_images(
674674
f"Images deleted in project {project_name}{'/' + folder_name if folder_name else ''}"
675675
)
676676

677+
def assign_items(
678+
self, project: Union[NotEmptyStr, dict], items: List[str], user: str
679+
):
680+
"""Assigns items to a user. The assignment role, QA or Annotator, will
681+
be deduced from the user's role in the project. The type of the objects` image, video or text
682+
will be deduced from the project type. With SDK, the user can be
683+
assigned to a role in the project with the share_project function.
684+
685+
:param project: project name or folder path (e.g., "project1/folder1")
686+
:type project: str
687+
:param items: list of items to assign
688+
:type item_names: list of str
689+
:param user: user email
690+
:type user: str
691+
"""
692+
693+
project_name, folder_name = extract_project_folder(project)
694+
695+
response = self.controller.assign_items(project_name, folder_name, items, user)
696+
697+
if not response.errors:
698+
logger.info(f"Assign items to user {user}")
699+
else:
700+
raise AppException(response.errors)
701+
702+
def unassign_items(
703+
self, project: Union[NotEmptyStr, dict], items: List[NotEmptyStr]
704+
):
705+
"""Removes assignment of given items for all assignees. With SDK,
706+
the user can be assigned to a role in the project with the share_project
707+
function.
708+
709+
:param project: project name or folder path (e.g., "project1/folder1")
710+
:type project: str
711+
:param items: list of items to unassign
712+
:type item_names: list of str
713+
"""
714+
project_name, folder_name = extract_project_folder(project)
715+
716+
response = self.controller.un_assign_items(
717+
project_name=project_name, folder_name=folder_name, item_names=items
718+
)
719+
if response.errors:
720+
raise AppException(response.errors)
721+
677722
def assign_images(
678723
self, project: Union[NotEmptyStr, dict], image_names: List[str], user: str
679724
):
@@ -688,6 +733,14 @@ def assign_images(
688733
:param user: user email
689734
:type user: str
690735
"""
736+
737+
warning_msg = (
738+
"We're deprecating the assign_images function. Please use assign_items instead."
739+
"Learn more. \n"
740+
"https://superannotate.readthedocs.io/en/stable/superannotate.sdk.html#superannotate.assign_items"
741+
)
742+
logger.warning(warning_msg)
743+
warnings.warn(warning_msg, DeprecationWarning)
691744
project_name, folder_name = extract_project_folder(project)
692745
project = self.controller.get_project_metadata(project_name).data
693746

@@ -726,18 +779,26 @@ def assign_images(
726779
def unassign_images(
727780
self, project: Union[NotEmptyStr, dict], image_names: List[NotEmptyStr]
728781
):
729-
"""Removes assignment of given images for all assignees.With SDK,
782+
"""Removes assignment of given images for all assignees. With SDK,
730783
the user can be assigned to a role in the project with the share_project
731784
function.
732785
733786
:param project: project name or folder path (e.g., "project1/folder1")
734787
:type project: str
735-
:param image_names: list of image unassign
788+
:param image_names: list of images to unassign
736789
:type image_names: list of str
737790
"""
791+
792+
warning_msg = (
793+
"We're deprecating the unassign_images function. Please use unassign_items instead."
794+
"Learn more. \n"
795+
"https://superannotate.readthedocs.io/en/stable/superannotate.sdk.html#superannotate.unassign_items"
796+
)
797+
logger.warning(warning_msg)
798+
warnings.warn(warning_msg, DeprecationWarning)
738799
project_name, folder_name = extract_project_folder(project)
739800

740-
response = self.controller.un_assign_images(
801+
response = self.controller.un_assign_items(
741802
project_name=project_name, folder_name=folder_name, image_names=image_names
742803
)
743804
if response.errors:

src/superannotate/lib/core/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from os.path import expanduser
22

3+
from superannotate.lib.core.config import Config
34
from superannotate.lib.core.enums import AnnotationStatus
45
from superannotate.lib.core.enums import ImageQuality
56
from superannotate.lib.core.enums import ProjectState
@@ -12,6 +13,9 @@
1213
from superannotate.lib.core.enums import UserRole
1314

1415

16+
CONFIG = Config()
17+
18+
1519
CONFIG_PATH = "~/.superannotate/config.json"
1620
CONFIG_FILE_LOCATION = expanduser(CONFIG_PATH)
1721
LOG_FILE_LOCATION = expanduser("~/.superannotate/sa.log")
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import threading
2+
from typing import Dict
3+
4+
from dataclasses import dataclass
5+
from dataclasses import field
6+
7+
8+
class Session:
9+
def __init__(self):
10+
self.pk = threading.get_ident()
11+
self._data_dict = {}
12+
13+
def __enter__(self):
14+
return self
15+
16+
def __exit__(self, type, value, traceback):
17+
if type is not None:
18+
return False
19+
20+
def __del__(self):
21+
Config().delete_current_session()
22+
23+
@property
24+
def data(self):
25+
return self._data_dict
26+
27+
@staticmethod
28+
def get_current_session():
29+
return Config().get_current_session()
30+
31+
def __setitem__(self, key, item):
32+
self._data_dict[key] = item
33+
34+
def __getitem__(self, key):
35+
return self._data_dict[key]
36+
37+
def __repr__(self):
38+
return repr(self._data_dict)
39+
40+
def clear(self):
41+
return self._data_dict.clear()
42+
43+
44+
class Singleton(type):
45+
_instances = {}
46+
_lock = threading.Lock()
47+
48+
def __call__(cls, *args, **kwargs):
49+
if cls not in cls._instances:
50+
with cls._lock:
51+
if cls not in cls._instances:
52+
cls._instances[cls] = super().__call__(*args, **kwargs)
53+
return cls._instances[cls]
54+
55+
56+
@dataclass()
57+
class Config(metaclass=Singleton):
58+
SESSIONS: Dict[int, Session] = field(default_factory=dict)
59+
60+
def get_current_session(self):
61+
session = self.SESSIONS.get(threading.get_ident())
62+
if not session:
63+
session = Session()
64+
self.SESSIONS.update({session.pk: session})
65+
return session
66+
67+
def delete_current_session(self):
68+
ident = threading.get_ident()
69+
if ident in self.SESSIONS:
70+
del self.SESSIONS[ident]

src/superannotate/lib/core/reporter.py

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from typing import Union
77

88
import tqdm
9+
from lib.core import CONFIG
910
from superannotate.logger import get_default_logger
1011

1112

@@ -31,59 +32,13 @@ def init_spin(self):
3132
sys.stdout.write("\b")
3233

3334

34-
class Session:
35-
def __init__(self):
36-
self.pk = threading.get_ident()
37-
self._data_dict = {}
38-
39-
def __enter__(self):
40-
return self
41-
42-
def __exit__(self, type, value, traceback):
43-
if type is not None:
44-
return False
45-
46-
def __del__(self):
47-
globs = globals()
48-
if "SESSIONS" in globs and globs["SESSIONS"].get(self.pk):
49-
del globs["SESSIONS"][self.pk]
50-
51-
@property
52-
def data(self):
53-
return self._data_dict
54-
55-
@staticmethod
56-
def get_current_session():
57-
globs = globals()
58-
if not globs.get("SESSIONS") or not globs["SESSIONS"].get(
59-
threading.get_ident()
60-
):
61-
session = Session()
62-
globals().update({"SESSIONS": {session.pk: session}})
63-
return session
64-
return globs["SESSIONS"][threading.get_ident()]
65-
66-
def __setitem__(self, key, item):
67-
self._data_dict[key] = item
68-
69-
def __getitem__(self, key):
70-
return self._data_dict[key]
71-
72-
def __repr__(self):
73-
return repr(self._data_dict)
74-
75-
def clear(self):
76-
return self._data_dict.clear()
77-
78-
7935
class Reporter:
8036
def __init__(
8137
self,
8238
log_info: bool = True,
8339
log_warning: bool = True,
8440
disable_progress_bar: bool = False,
8541
log_debug: bool = True,
86-
session: Session = None,
8742
):
8843
self.logger = get_default_logger()
8944
self._log_info = log_info
@@ -95,7 +50,7 @@ def __init__(
9550
self.debug_messages = []
9651
self.custom_messages = defaultdict(set)
9752
self.progress_bar = None
98-
self.session = session
53+
self.session = CONFIG.get_current_session()
9954
self._spinner = None
10055

10156
def start_spinner(self):

src/superannotate/lib/core/response.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ def __init__(self, status: str = None, data: Union[dict, list] = None):
88
self._report = []
99
self._errors = []
1010

11+
def __str__(self):
12+
return f"Response object with status:{self.status}, data : {self.data}, errors: {self.errors} "
13+
1114
@property
1215
def data(self):
1316
return self._data
@@ -30,7 +33,7 @@ def report_messages(self):
3033

3134
@property
3235
def status(self):
33-
return self.data
36+
return self._status
3437

3538
@status.setter
3639
def status(self, value):

src/superannotate/lib/core/serviceproviders.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,16 @@ def assign_images(
175175
):
176176
raise NotImplementedError
177177

178+
def assign_items(
179+
self,
180+
team_id: int,
181+
project_id: int,
182+
folder_name: str,
183+
user: str,
184+
item_names: list,
185+
):
186+
raise NotImplementedError
187+
178188
def get_bulk_images(
179189
self, project_id: int, team_id: int, folder_id: int, images: List[str]
180190
) -> List[dict]:
@@ -202,6 +212,15 @@ def un_assign_images(
202212
):
203213
raise NotImplementedError
204214

215+
def un_assign_items(
216+
self,
217+
team_id: int,
218+
project_id: int,
219+
folder_name: str,
220+
item_names: list,
221+
):
222+
raise NotImplementedError
223+
205224
def un_share_project(
206225
self,
207226
team_id: int,

0 commit comments

Comments
 (0)