Skip to content

Commit 207a687

Browse files
feat(LAB-3743): move copy label to backend resolver
1 parent 76e09e1 commit 207a687

File tree

3 files changed

+89
-3
lines changed

3 files changed

+89
-3
lines changed

src/kili/adapters/kili_api_gateway/label/operations.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,10 @@ def get_annotations_partial_query(
153153
{annotation_fragment}
154154
{inline_fragments}
155155
"""
156+
157+
158+
GQL_COPY_LABELS = """
159+
mutation CopyLabels($data: CopyLabelsInput!) {
160+
copyLabels(data: $data)
161+
}
162+
"""

src/kili/adapters/kili_api_gateway/label/operations_mixin.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from .formatters import load_label_json_fields
2525
from .mappers import append_label_data_mapper, append_to_labels_data_mapper, label_where_mapper
2626
from .operations import (
27+
GQL_COPY_LABELS,
2728
GQL_COUNT_LABELS,
2829
GQL_DELETE_LABELS,
2930
get_append_many_labels_mutation,
@@ -200,3 +201,15 @@ def create_honeypot_label(
200201
}
201202
result = self.graphql_client.execute(query, variables)
202203
return result["data"]
204+
205+
def copy_labels(self, src_asset_id: str, dst_asset_id: str, project_id: str) -> bool:
206+
"""Copy labels from one asset to another."""
207+
variables = {
208+
"data": {
209+
"srcAssetId": src_asset_id,
210+
"dstAssetId": dst_asset_id,
211+
"projectId": project_id,
212+
},
213+
}
214+
self.graphql_client.execute(GQL_COPY_LABELS, variables)
215+
return True

src/kili/services/copy_project/__init__.py

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import itertools
44
import logging
5+
import warnings
56
from typing import TYPE_CHECKING, Optional
67

78
from kili.adapters.kili_api_gateway.helpers.queries import QueryOptions
@@ -22,9 +23,13 @@ class ProjectCopier: # pylint: disable=too-few-public-methods
2223
"description",
2324
"id",
2425
"dataConnections.id",
26+
"inputType",
27+
"jsonInterface",
28+
"workflowVersion",
2529
)
2630

2731
def __init__(self, kili: "Kili") -> None:
32+
"""Simple initialization."""
2833
self.disable_tqdm = False
2934
self.kili = kili
3035

@@ -72,7 +77,7 @@ def copy_project( # pylint: disable=too-many-arguments
7277
),
7378
)
7479

75-
logger.info(f"Created new project {new_project_id}")
80+
logger.info("Created new project %s", new_project_id)
7681

7782
self.kili.update_properties_in_project(
7883
project_id=new_project_id,
@@ -84,7 +89,18 @@ def copy_project( # pylint: disable=too-many-arguments
8489

8590
if copy_labels:
8691
logger.info("Copying labels...")
87-
self._copy_labels(from_project_id, new_project_id)
92+
if src_project["workflowVersion"] == "V2":
93+
self._copy_labels(from_project_id=from_project_id, new_project_id=new_project_id)
94+
else:
95+
warnings.warn(
96+
"Warning: "
97+
"copying a project of an old workflow mode may cause problems in asset status and assignation. "
98+
"Consider creating a new project instead.",
99+
DeprecationWarning,
100+
)
101+
self._copy_labels_legacy(
102+
from_project_id=from_project_id, new_project_id=new_project_id
103+
)
88104

89105
return new_project_id
90106

@@ -100,8 +116,58 @@ def _generate_project_title(self, src_title: str) -> str:
100116
i += 1
101117
return new_title
102118

103-
# pylint: disable=too-many-locals
104119
def _copy_labels(self, from_project_id: str, new_project_id: str) -> None:
120+
"""Method to copy labels from the source project to the new project : applicable for WFV2."""
121+
nb_labels_to_copy = self.kili.kili_api_gateway.count_labels(
122+
LabelFilters(project_id=ProjectId(from_project_id))
123+
)
124+
125+
if nb_labels_to_copy == 0:
126+
return
127+
128+
assets_src_project = self.kili.kili_api_gateway.list_assets(
129+
AssetFilters(project_id=ProjectId(from_project_id)),
130+
["id", "externalId", "labels.id"],
131+
QueryOptions(disable_tqdm=True),
132+
)
133+
134+
assets_dst_project = self.kili.kili_api_gateway.list_assets(
135+
AssetFilters(project_id=ProjectId(new_project_id)),
136+
["id", "externalId"],
137+
QueryOptions(disable_tqdm=True),
138+
)
139+
140+
# Iterate on assets of the source project
141+
# to copy labels to the new projectq
142+
assets_src_project_list = [
143+
asset
144+
for asset in assets_src_project
145+
if "labels" in asset and asset["labels"] and len(asset["labels"]) > 0
146+
]
147+
assets_dst_project_map = {asset["externalId"]: asset["id"] for asset in assets_dst_project}
148+
149+
for src_asset in assets_src_project_list:
150+
src_asset_id = src_asset["id"]
151+
dst_asset_id = assets_dst_project_map.get(src_asset["externalId"])
152+
if not dst_asset_id:
153+
raise ValueError(
154+
f"Asset with externalId {src_asset['externalId']} not found in new project {new_project_id}."
155+
)
156+
157+
self.kili.kili_api_gateway.copy_labels(
158+
src_asset_id=src_asset_id,
159+
dst_asset_id=dst_asset_id,
160+
project_id=new_project_id,
161+
)
162+
163+
# pylint: disable=too-many-locals
164+
def _copy_labels_legacy(self, from_project_id: str, new_project_id: str) -> None:
165+
"""Legacy mlethod to copy labels from the source project to the new project : applicable for WFV1.
166+
167+
!!! warning
168+
This method is deprecated and will be removed in the next major release.
169+
Asset with send back labels are not supported (status wise) and asset assignation is not supported.
170+
"""
105171
assets_new_project = self.kili.kili_api_gateway.list_assets(
106172
AssetFilters(project_id=ProjectId(new_project_id)),
107173
["id", "externalId"],

0 commit comments

Comments
 (0)