Skip to content

Commit

Permalink
feat(LAB-2960): use existing project to create a new one (#1733)
Browse files Browse the repository at this point in the history
  • Loading branch information
FannyGaudin committed Jul 5, 2024
1 parent 2d12c48 commit adca525
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 34 deletions.
8 changes: 5 additions & 3 deletions src/kili/entrypoints/cli/project/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
def create_project(
api_key: Optional[str],
endpoint: Optional[str],
project_id: Optional[ProjectId],
interface: str,
project_id_src: str,
input_type,
Expand Down Expand Up @@ -83,8 +84,9 @@ def create_project(
json_interface=json_interface,
title=title,
description=description,
project_id=project_id,
)
project_id = result["id"]
new_project_id = result["id"]

project_url = get_project_url(project_id, kili.graphql_client.endpoint)
print(tabulate([[project_id, project_url]], headers=["ID", "URL"], tablefmt=tablefmt))
project_url = get_project_url(new_project_id, kili.graphql_client.endpoint)
print(tabulate([[new_project_id, project_url]], headers=["ID", "URL"], tablefmt=tablefmt))
3 changes: 3 additions & 0 deletions src/kili/presentation/client/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def create_project(
json_interface: Dict,
title: str,
description: str = "",
project_id: Optional[ProjectId] = None,
project_type: Optional[ProjectType] = None,
tags: Optional[ListOrTuple[str]] = None,
compliance_tags: Optional[ListOrTuple[ComplianceTag]] = None,
Expand All @@ -53,6 +54,7 @@ def create_project(
json_interface: The json parameters of the project, see Edit your interface.
title: Title of the project.
description: Description of the project.
project_id: Identifier of the project to copy.
project_type: Currently, one of:
- `IMAGE_CLASSIFICATION_MULTI`
Expand Down Expand Up @@ -97,6 +99,7 @@ def create_project(
json_interface=json_interface,
title=title,
description=description,
project_id=project_id,
project_type=project_type,
compliance_tags=compliance_tags,
)
Expand Down
93 changes: 62 additions & 31 deletions src/kili/use_cases/project/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,49 @@ def create_project(
json_interface: Dict,
title: str,
description: str,
project_id: Optional[ProjectId],
project_type: Optional[ProjectType],
compliance_tags: Optional[ListOrTuple[ComplianceTag]],
) -> ProjectId:
"""Create a project."""
project_id = self._kili_api_gateway.create_project(
input_type=input_type,
json_interface=json_interface,
title=title,
description=description,
project_type=project_type,
compliance_tags=compliance_tags,
)
"""Create or copy a project if project_id is set."""
if project_id is not None:
project_copied = self._kili_api_gateway.get_project(
project_id=project_id, fields=["jsonInterface", "instructions"]
)
project_tag = self._kili_api_gateway.list_tags_by_project(
project_id=project_id, fields=["id"]
)
new_project_id = self._kili_api_gateway.create_project(
input_type=input_type,
json_interface=project_copied["jsonInterface"],
title=title,
description=description,
project_type=project_type,
compliance_tags=compliance_tags,
)
if project_copied["instructions"]:
self.update_properties_in_project(
project_id=new_project_id,
instructions=project_copied["instructions"],
)
tags_of_orga = self._kili_api_gateway.list_tags_by_org(fields=("id",))
tags_of_orga_ids = [tag["id"] for tag in tags_of_orga]

for tag in project_tag:
if tag["id"] not in tags_of_orga_ids:
raise ValueError(
f"Tag {tag['id']} doesn't belong to your organization and was not copied."
)
self._kili_api_gateway.check_tag(project_id=new_project_id, tag_id=tag["id"])
else:
new_project_id = self._kili_api_gateway.create_project(
input_type=input_type,
json_interface=json_interface,
title=title,
description=description,
project_type=project_type,
compliance_tags=compliance_tags,
)

# The project is not immediately available after creation
for attempt in Retrying(
Expand All @@ -49,9 +80,9 @@ def create_project(
reraise=True,
):
with attempt:
_ = self._kili_api_gateway.get_project(project_id=project_id, fields=("id",))
_ = self._kili_api_gateway.get_project(project_id=new_project_id, fields=("id",))

return ProjectId(project_id)
return ProjectId(new_project_id)

def list_projects(
self,
Expand All @@ -71,26 +102,26 @@ def update_properties_in_project(
self,
project_id: ProjectId,
*,
can_navigate_between_assets: Optional[bool],
can_skip_asset: Optional[bool],
compliance_tags: Optional[ListOrTuple[ComplianceTag]],
consensus_mark: Optional[float],
consensus_tot_coverage: Optional[int],
description: Optional[str],
honeypot_mark: Optional[float],
instructions: Optional[str],
input_type: Optional[InputType],
json_interface: Optional[Dict],
min_consensus_size: Optional[int],
number_of_assets: Optional[int],
number_of_skipped_assets: Optional[int],
number_of_remaining_assets: Optional[int],
number_of_reviewed_assets: Optional[int],
review_coverage: Optional[int],
should_relaunch_kpi_computation: Optional[bool],
title: Optional[str],
use_honeypot: Optional[bool],
metadata_types: Optional[Dict],
can_navigate_between_assets: Optional[bool] = None,
can_skip_asset: Optional[bool] = None,
compliance_tags: Optional[ListOrTuple[ComplianceTag]] = None,
consensus_mark: Optional[float] = None,
consensus_tot_coverage: Optional[int] = None,
description: Optional[str] = None,
honeypot_mark: Optional[float] = None,
instructions: Optional[str] = None,
input_type: Optional[InputType] = None,
json_interface: Optional[Dict] = None,
min_consensus_size: Optional[int] = None,
number_of_assets: Optional[int] = None,
number_of_skipped_assets: Optional[int] = None,
number_of_remaining_assets: Optional[int] = None,
number_of_reviewed_assets: Optional[int] = None,
review_coverage: Optional[int] = None,
should_relaunch_kpi_computation: Optional[bool] = None,
title: Optional[str] = None,
use_honeypot: Optional[bool] = None,
metadata_types: Optional[Dict] = None,
) -> Dict[str, object]:
"""Update properties in a project."""
if consensus_tot_coverage is not None and not 0 <= consensus_tot_coverage <= 100:
Expand Down
87 changes: 87 additions & 0 deletions tests/integration/use_cases/test_project.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
from types import GeneratorType

import pytest

from kili.adapters.kili_api_gateway.helpers.queries import QueryOptions
from kili.adapters.kili_api_gateway.kili_api_gateway import KiliAPIGateway
from kili.adapters.kili_api_gateway.project.types import ProjectDataKiliAPIGatewayInput
from kili.domain.project import ProjectFilters, ProjectId
from kili.domain.types import ListOrTuple
from kili.use_cases.project.project import ProjectUseCases

interface = {
"jobs": {
"JOB_0": {
"content": {
"categories": {
"OBJECT_A": {"children": [], "name": "Object A"},
"OBJECT_B": {"children": [], "name": "Object B"},
},
"input": "radio",
},
"instruction": "Categories",
"isChild": False,
"mlTask": "CLASSIFICATION",
"models": {},
"isVisible": True,
"required": 1,
}
}
}


def test_when_create_project_it_works(kili_api_gateway: KiliAPIGateway):
kili_api_gateway.create_project.return_value = "fake_project_id"
Expand All @@ -17,6 +39,7 @@ def test_when_create_project_it_works(kili_api_gateway: KiliAPIGateway):
json_interface={},
title="test",
description="description",
project_id=None,
project_type=None,
compliance_tags=None,
)
Expand All @@ -25,6 +48,70 @@ def test_when_create_project_it_works(kili_api_gateway: KiliAPIGateway):
assert project_id == "fake_project_id"


def test_when_create_project_with_project_id_it_works(kili_api_gateway: KiliAPIGateway):
# Given
tags = [
{"id": "tag1_id", "label": "tag1"},
{"id": "tag2_id", "label": "tag2"},
]
kili_api_gateway.create_project.return_value = "fake_copied_project_id"
kili_api_gateway.get_project.return_value = {
"jsonInterface": interface,
"instructions": "fake_instructions",
}
kili_api_gateway.list_tags_by_project.return_value = tags
kili_api_gateway.list_tags_by_org.return_value = tags

# When
project_id = ProjectUseCases(kili_api_gateway).create_project(
input_type="TEXT",
json_interface=interface,
title="test",
description="description",
project_id=ProjectId("fake_project_id"),
project_type=None,
compliance_tags=None,
)

# Then
assert project_id == "fake_copied_project_id"


def test_when_create_project_with_project_id_it_throw_an_error_if_tags_do_not_belong_to_the_same_organisation(
kili_api_gateway: KiliAPIGateway,
):
# Given
tags = [
{"id": "tag1_id", "label": "tag1"},
]
org_tags = [
{"id": "tag2_id", "label": "tag2"},
]
kili_api_gateway.create_project.return_value = "fake_copied_project_id"
kili_api_gateway.get_project.return_value = {
"jsonInterface": interface,
"instructions": "fake_instructions",
}
kili_api_gateway.list_tags_by_project.return_value = tags
kili_api_gateway.list_tags_by_org.return_value = org_tags

# When
project_use_cases = ProjectUseCases(kili_api_gateway)
with pytest.raises(
ValueError,
match="Tag tag1_id doesn't belong to your organization and was not copied.",
):
project_use_cases.create_project(
input_type="TEXT",
json_interface=interface,
title="test",
description="description",
project_id=ProjectId("fake_project_id"),
project_type=None,
compliance_tags=None,
)


def test_when_i_query_projects_i_get_a_generator_of_projects(kili_api_gateway: KiliAPIGateway):
# Given
kili_projects = [
Expand Down

0 comments on commit adca525

Please sign in to comment.