Skip to content

Commit 523e200

Browse files
committed
clone_project log fix
1 parent 8b1ef17 commit 523e200

File tree

5 files changed

+37
-19
lines changed

5 files changed

+37
-19
lines changed

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,11 @@ def create_project(
357357
if step["className"] not in class_names:
358358
invalid_classes.append(step["className"])
359359
if invalid_classes:
360+
seen = set()
361+
seen_add = seen.add
362+
invalid_classes = [i for i in invalid_classes if not (i in seen or seen_add(i))]
360363
raise AppException(
361-
f"There are no [{', '.join(set(invalid_classes))}] classes created in the project."
364+
f"There are no [{', '.join(invalid_classes)}] classes created in the project."
362365
)
363366
project_response = self.controller.projects.create(
364367
entities.ProjectEntity(
@@ -477,6 +480,8 @@ def clone_project(
477480
else:
478481
project_copy.description = project.description
479482
project_copy.name = project_name
483+
if project.type in (constants.ProjectType.VECTOR, constants.ProjectType.PIXEL):
484+
project.upload_state = enums.UploadState.INITIAL
480485
create_response = self.controller.projects.create(project_copy)
481486
create_response.raise_for_status()
482487
new_project = create_response.data
@@ -494,14 +499,28 @@ def clone_project(
494499
)
495500
classes_response.raise_for_status()
496501
project.classes = classes_response.data
497-
if copy_workflow:
502+
if copy_workflow:
503+
if not copy_annotation_classes:
504+
logger.info(f"Skipping the workflow clone from {from_project} to {project_name}.")
505+
else:
498506
logger.info(f"Cloning workflow from {from_project} to {project_name}.")
499507
workflow_response = self.controller.projects.set_workflows(
500508
new_project, project.workflows
501509
)
502510
workflow_response.raise_for_status()
503511
project.workflows = self.controller.projects.list_workflow(project).data
504-
return ProjectSerializer(new_project).serialize()
512+
response = self.controller.projects.get_metadata(
513+
new_project,
514+
include_settings=copy_settings,
515+
include_workflow=copy_workflow,
516+
include_contributors=copy_contributors,
517+
include_annotation_classes=copy_annotation_classes,
518+
include_complete_image_count=True,
519+
)
520+
521+
if response.errors:
522+
raise AppException(response.errors)
523+
return ProjectSerializer(response.data).serialize()
505524

506525
def create_folder(self, project: NotEmptyStr, folder_name: NotEmptyStr):
507526
"""Create a new folder in the project.
@@ -907,7 +926,7 @@ def assign_folder(
907926
raise AppException(response.errors)
908927

909928
contributors = response.data.users
910-
verified_users = [i["user_id"] for i in contributors]
929+
verified_users = [i.user_id for i in contributors]
911930
verified_users = set(users).intersection(set(verified_users))
912931
unverified_contributor = set(users) - verified_users
913932

@@ -2155,7 +2174,7 @@ def add_contributors_to_project(
21552174
"""
21562175
project = self.controller.projects.get_by_name(project).data
21572176
contributors = [
2158-
entities.ContributorEntity(email=email, user_role=constants.UserRole(role))
2177+
entities.ContributorEntity(user_id=email, user_role=constants.UserRole(role))
21592178
for email in emails
21602179
]
21612180
response = self.controller.projects.add_contributors(

src/superannotate/lib/core/entities/project.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,9 @@ def __copy__(self):
7979

8080

8181
class ContributorEntity(BaseModel):
82-
id: Optional[str]
8382
first_name: Optional[str]
8483
last_name: Optional[str]
85-
email: str
84+
user_id: str
8685
user_role: UserRole
8786

8887
class Config:
@@ -103,7 +102,7 @@ class ProjectEntity(TimedBaseModel):
103102
folder_id: Optional[int]
104103
sync_status: Optional[int]
105104
upload_state: Optional[int]
106-
users: Optional[List[Any]] = []
105+
users: Optional[List[ContributorEntity]] = []
107106
unverified_users: Optional[List[Any]] = []
108107
contributors: List[ContributorEntity] = []
109108
settings: List[SettingEntity] = []
@@ -169,6 +168,6 @@ class TeamEntity(BaseModel):
169168
type: Optional[str]
170169
user_role: Optional[str]
171170
is_default: Optional[bool]
172-
users: Optional[List[ContributorEntity]]
173-
pending_invitations: Optional[List]
171+
users: Optional[List[Any]]
172+
pending_invitations: Optional[List[Any]]
174173
creator_id: Optional[str]

src/superannotate/lib/core/usecases/projects.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ def execute(self):
296296

297297
logger.info(
298298
f"Created project {entity.name} (ID {entity.id}) "
299-
f"with type {constances.ProjectType.get_name(self._response.data.type)}"
299+
f"with type {constances.ProjectType.get_name(self._response.data.type)}."
300300
)
301301
return self._response
302302

@@ -691,7 +691,7 @@ def __init__(
691691
def validate_emails(self):
692692
email_entity_map = {}
693693
for c in self._contributors:
694-
email_entity_map[c.email] = c
694+
email_entity_map[c.user_id] = c
695695
len_unique, len_provided = len(email_entity_map), len(self._contributors)
696696
if len_unique < len_provided:
697697
logger.info(
@@ -702,10 +702,10 @@ def validate_emails(self):
702702
def execute(self):
703703
if self.is_valid():
704704
team_users = set()
705-
project_users = {user["user_id"] for user in self._project.users}
705+
project_users = {user.user_id for user in self._project.users}
706706
for user in self._team.users:
707-
if user.user_role > constances.UserRole.ADMIN.value:
708-
team_users.add(user.email)
707+
if user['user_role'] > constances.UserRole.ADMIN.value:
708+
team_users.add(user['email'])
709709
# collecting pending team users which is not admin
710710
for user in self._team.pending_invitations:
711711
if user["user_role"] > constances.UserRole.ADMIN.value:
@@ -719,7 +719,7 @@ def execute(self):
719719
to_skip = []
720720
to_add = []
721721
for contributor in self._contributors:
722-
role_email_map[contributor.user_role].append(contributor.email)
722+
role_email_map[contributor.user_role].append(contributor.user_id)
723723
for role, emails in role_email_map.items():
724724
_to_add = list(team_users.intersection(emails) - project_users)
725725
to_add.extend(_to_add)

src/superannotate/lib/infrastructure/services/annotation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,9 @@ async def upload_small_annotations(
294294
data=data,
295295
)
296296
if not _response.ok:
297+
logger.debug(f"Status code {str(_response.status)}")
297298
logger.debug(await _response.text())
298299
raise AppException("Can't upload annotations.")
299-
logger.debug(_response.status)
300300
data_json = await _response.json()
301301
response = UploadAnnotationsResponse()
302302
response.status = _response.status

tests/integration/projects/test_clone_project.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def test_clone_project(self):
9696
if setting["attribute"].lower() == "imageQuality".lower():
9797
self.assertEqual(setting["value"], self.IMAGE_QUALITY)
9898
break
99-
self.assertEqual(new_project["description"], f"Copy of {self.PROJECT_NAME_1}.")
99+
self.assertEqual(new_project["description"], self.PROJECT_DESCRIPTION)
100100
self.assertEqual(new_project["type"].lower(), "vector")
101101

102102
ann_classes = sa.search_annotation_classes(self.PROJECT_NAME_2)
@@ -211,7 +211,7 @@ def test_clone_video_project(self):
211211
)
212212
self.assertEqual(new_project["name"], self.PROJECT_NAME_2)
213213
self.assertEqual(new_project["type"].lower(), "video")
214-
self.assertEqual(new_project["description"], f"Copy of {self.PROJECT_NAME_1}.")
214+
self.assertEqual(new_project["description"], self._project_1['description'])
215215

216216
def test_clone_video_project_frame_mode_on(self):
217217
self._project_1 = sa.create_project(

0 commit comments

Comments
 (0)