Skip to content

Commit 8f4a839

Browse files
authored
Merge pull request #555 from Labelbox/pn/al-2183
AL-2183 - Add MediaType support to Project
2 parents d2111e2 + 044c679 commit 8f4a839

File tree

8 files changed

+144
-46
lines changed

8 files changed

+144
-46
lines changed

examples/basics/projects.ipynb

Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
"cells": [
33
{
44
"cell_type": "markdown",
5+
"metadata": {},
56
"source": [
67
"<td>\n",
78
" <a target=\"_blank\" href=\"https://labelbox.com\" ><img src=\"https://labelbox.com/blog/content/images/2021/02/logo-v4.svg\" width=256/></a>\n",
89
"</td>"
9-
],
10-
"metadata": {}
10+
]
1111
},
1212
{
1313
"cell_type": "markdown",
14+
"metadata": {},
1415
"source": [
1516
"<td>\n",
1617
"<a href=\"https://colab.research.google.com/github/Labelbox/labelbox-python/blob/develop/examples/basics/projects.ipynb\" target=\"_blank\"><img\n",
@@ -21,18 +22,18 @@
2122
"<a href=\"https://github.com/Labelbox/labelbox-python/tree/develop/examples/basics/projects.ipynb\" target=\"_blank\"><img\n",
2223
"src=\"https://img.shields.io/badge/GitHub-100000?logo=github&logoColor=white\" alt=\"GitHub\"></a>\n",
2324
"</td>"
24-
],
25-
"metadata": {}
25+
]
2626
},
2727
{
2828
"cell_type": "markdown",
29+
"metadata": {},
2930
"source": [
3031
"# Projects"
31-
],
32-
"metadata": {}
32+
]
3333
},
3434
{
3535
"cell_type": "markdown",
36+
"metadata": {},
3637
"source": [
3738
"* A project can be thought of as a specific labeling task on a set of labels\n",
3839
"* That set of labels is defined by the datasets attached to the project\n",
@@ -41,123 +42,129 @@
4142
"\n",
4243
"** Note that there is a lot of advanced usage that is not covered in this notebook. See project_setup for those functions.\n",
4344
"* Also note that deprecated functions are not explained here."
44-
],
45-
"metadata": {}
45+
]
4646
},
4747
{
4848
"cell_type": "code",
4949
"execution_count": 1,
50+
"metadata": {},
51+
"outputs": [],
5052
"source": [
5153
"!pip install labelbox"
52-
],
53-
"outputs": [],
54-
"metadata": {}
54+
]
5555
},
5656
{
5757
"cell_type": "code",
5858
"execution_count": 2,
59+
"metadata": {},
60+
"outputs": [],
5961
"source": [
6062
"from labelbox import Client\n",
63+
"from labelbox.schema.media_type import MediaType\n",
6164
"import os"
62-
],
63-
"outputs": [],
64-
"metadata": {}
65+
]
6566
},
6667
{
6768
"cell_type": "markdown",
69+
"metadata": {},
6870
"source": [
6971
"# API Key and Client\n",
7072
"Provide a valid api key below in order to properly connect to the Labelbox Client."
71-
],
72-
"metadata": {}
73+
]
7374
},
7475
{
7576
"cell_type": "code",
7677
"execution_count": 5,
78+
"metadata": {},
79+
"outputs": [],
7780
"source": [
7881
"# Add your api key\n",
7982
"API_KEY = None\n",
8083
"client = Client(api_key=API_KEY)"
81-
],
82-
"outputs": [],
83-
"metadata": {}
84+
]
8485
},
8586
{
8687
"cell_type": "markdown",
88+
"metadata": {},
8789
"source": [
8890
"### Create\n"
89-
],
90-
"metadata": {}
91+
]
9192
},
9293
{
9394
"cell_type": "code",
9495
"execution_count": 6,
96+
"metadata": {},
97+
"outputs": [],
9598
"source": [
96-
"# Creates an empty project\n",
99+
"# Creates an empty project without a media type\n",
97100
"project = client.create_project(name=\"my-test-project\",\n",
98-
" description=\"a description\")"
99-
],
100-
"outputs": [],
101-
"metadata": {}
101+
" description=\"a description\")\n",
102+
"\n",
103+
"# Creates an empty project a media type\n",
104+
"project = client.create_project(name=\"my-test-project\",\n",
105+
" description=\"a description\",\n",
106+
" media_type=MediaType.Image)"
107+
]
102108
},
103109
{
104110
"cell_type": "markdown",
111+
"metadata": {},
105112
"source": [
106113
"### Read"
107-
],
108-
"metadata": {}
114+
]
109115
},
110116
{
111117
"cell_type": "code",
112118
"execution_count": null,
119+
"metadata": {},
120+
"outputs": [],
113121
"source": [
114122
"# Note the project is not setup (so a lot of these fiels are empty). Follow the project setup workflow\n",
115123
"print(\"Project is not setup yet:\", project.setup_complete is None)\n",
116124
"print(\"Project name:\", project.name)\n",
117125
"print(\"Project description:\", project.description)\n",
126+
"print(\"Media Type:\", project.media_type)\n",
118127
"print(\"Dataset:\", list(project.datasets()))\n",
119128
"print(\"Ontology:\", project.ontology().normalized)\n",
120129
"print(\"Benchmarks:\", project.benchmarks())"
121-
],
122-
"outputs": [],
123-
"metadata": {}
130+
]
124131
},
125132
{
126133
"cell_type": "markdown",
134+
"metadata": {},
127135
"source": [
128136
"### Update\n",
129137
"\n"
130-
],
131-
"metadata": {}
138+
]
132139
},
133140
{
134141
"cell_type": "code",
135142
"execution_count": null,
143+
"metadata": {},
144+
"outputs": [],
136145
"source": [
137146
"# Attach dataset\n",
138147
"ds = client.create_dataset(name=\"test-ds\")\n",
139148
"project.datasets.connect(ds)\n",
140149
"print([ds.name for ds in project.datasets()])\n",
141150
"ds.delete()"
142-
],
143-
"outputs": [],
144-
"metadata": {}
151+
]
145152
},
146153
{
147154
"cell_type": "markdown",
155+
"metadata": {},
148156
"source": [
149157
"### Delete"
150-
],
151-
"metadata": {}
158+
]
152159
},
153160
{
154161
"cell_type": "code",
155162
"execution_count": 9,
163+
"metadata": {},
164+
"outputs": [],
156165
"source": [
157166
"project.delete()"
158-
],
159-
"outputs": [],
160-
"metadata": {}
167+
]
161168
}
162169
],
163170
"metadata": {
@@ -181,4 +188,4 @@
181188
},
182189
"nbformat": 4,
183190
"nbformat_minor": 5
184-
}
191+
}

labelbox/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@
3333
from labelbox.schema.iam_integration import IAMIntegration
3434
from labelbox.schema.resource_tag import ResourceTag
3535
from labelbox.schema.project_resource_tag import ProjectResourceTag
36+
from labelbox.schema.media_type import MediaType

labelbox/client.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
from labelbox.schema.project import Project
3333
from labelbox.schema.role import Role
3434

35+
from labelbox.schema.media_type import MediaType
36+
3537
logger = logging.getLogger(__name__)
3638

3739
_LABELBOX_API_KEY = "LABELBOX_API_KEY"
@@ -611,6 +613,15 @@ def create_project(self, **kwargs) -> Project:
611613
InvalidAttributeError: If the Project type does not contain
612614
any of the attribute names given in kwargs.
613615
"""
616+
media_type = kwargs.get("media_type")
617+
if media_type:
618+
if MediaType.is_supported(media_type):
619+
kwargs["media_type"] = media_type.value
620+
else:
621+
raise TypeError(f"{media_type} is not a valid media type. Use"
622+
f" any of {MediaType.get_supported_members()}"
623+
" from MediaType. Example: MediaType.Image.")
624+
614625
return self._create(Entity.Project, kwargs)
615626

616627
def get_roles(self) -> List[Role]:

labelbox/orm/db_object.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def _set_field_values(self, field_values):
6969
"Failed to convert value '%s' to datetime for "
7070
"field %s", value, field)
7171
elif isinstance(field.field_type, Field.EnumType):
72-
value = field.field_type.enum_cls[value]
72+
value = field.field_type.enum_cls(value)
7373
setattr(self, field.name, value)
7474

7575
def __repr__(self):

labelbox/schema/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@
2020
import labelbox.schema.data_row_metadata
2121
import labelbox.schema.batch
2222
import labelbox.schema.iam_integration
23+
import labelbox.schema.media_type

labelbox/schema/media_type.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from enum import Enum
2+
3+
4+
class MediaType(Enum):
5+
"""add DOCUMENT, GEOSPATIAL_TILE, SIMPLE_TILE to match the UI choices"""
6+
Audio = "AUDIO"
7+
Conversational = "CONVERSATIONAL"
8+
Dicom = "DICOM"
9+
Document = "PDF"
10+
Geospatial_Tile = "TMS_GEO"
11+
Image = "IMAGE"
12+
Json = "JSON"
13+
Pdf = "PDF"
14+
Simple_Tile = "TMS_SIMPLE"
15+
Text = "TEXT"
16+
Tms_Geo = "TMS_GEO"
17+
Tms_Simple = "TMS_SIMPLE"
18+
Video = "VIDEO"
19+
Unknown = "UNKNOWN"
20+
Unsupported = "UNSUPPORTED"
21+
22+
@classmethod
23+
def _missing_(cls, name):
24+
"""Handle missing null data types for projects
25+
created without setting allowedMediaType
26+
Handle upper case names for compatibility with
27+
the GraphQL"""
28+
29+
if name is None:
30+
return cls.Unknown
31+
32+
for member in cls.__members__:
33+
if member.name == name.upper():
34+
return member
35+
36+
@classmethod
37+
def is_supported(cls, value):
38+
return isinstance(value,
39+
cls) and value not in [cls.Unknown, cls.Unsupported]
40+
41+
@classmethod
42+
def get_supported_members(cls):
43+
return [
44+
item for item in cls.__members__
45+
if item not in ["Unknown", "Unsupported"]
46+
]

labelbox/schema/project.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import enum
1+
from enum import Enum
22
import json
33
import logging
44
import time
@@ -19,6 +19,7 @@
1919
from labelbox.orm.model import Entity, Field, Relationship
2020
from labelbox.pagination import PaginatedCollection
2121
from labelbox.schema.resource_tag import ResourceTag
22+
from labelbox.schema.media_type import MediaType
2223

2324
if TYPE_CHECKING:
2425
from labelbox import BulkImportRequest
@@ -63,6 +64,7 @@ class Project(DbObject, Updateable, Deletable):
6364
benchmarks (Relationship): `ToMany` relationship to Benchmark
6465
ontology (Relationship): `ToOne` relationship to Ontology
6566
"""
67+
6668
name = Field.String("name")
6769
description = Field.String("description")
6870
updated_at = Field.DateTime("updated_at")
@@ -71,6 +73,8 @@ class Project(DbObject, Updateable, Deletable):
7173
last_activity_time = Field.DateTime("last_activity_time")
7274
auto_audit_number_of_labels = Field.Int("auto_audit_number_of_labels")
7375
auto_audit_percentage = Field.Float("auto_audit_percentage")
76+
# Bind data_type and allowedMediaTYpe using the GraphQL type MediaType
77+
media_type = Field.Enum(MediaType, "media_type", "allowedMediaType")
7478

7579
# Relationships
7680
datasets = Relationship.ToMany("Dataset", True)
@@ -85,7 +89,7 @@ class Project(DbObject, Updateable, Deletable):
8589
benchmarks = Relationship.ToMany("Benchmark", False)
8690
ontology = Relationship.ToOne("Ontology", True)
8791

88-
class QueueMode(enum.Enum):
92+
class QueueMode(Enum):
8993
Batch = "Batch"
9094
Dataset = "Dataset"
9195

@@ -94,6 +98,15 @@ def update(self, **kwargs):
9498
if mode:
9599
self._update_queue_mode(mode)
96100

101+
media_type = kwargs.get("media_type")
102+
if media_type:
103+
if MediaType.is_supported(media_type):
104+
kwargs["media_type"] = media_type.value
105+
else:
106+
raise TypeError(f"{media_type} is not a valid media type. Use"
107+
f" any of {MediaType.get_supported_members()}"
108+
" from MediaType. Example: MediaType.Image.")
109+
97110
return super().update(**kwargs)
98111

99112
def members(self) -> PaginatedCollection:

tests/integration/test_project.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from labelbox import Project, LabelingFrontend, Dataset
88
from labelbox.exceptions import InvalidQueryError
9+
from labelbox.schema.media_type import MediaType
910

1011

1112
def test_project(client, rand_gen):
@@ -219,4 +220,22 @@ def test_batches(configured_project: Project, dataset: Dataset, image_url):
219220
configured_project.create_batch(batch_two, [data_rows[1]])
220221

221222
names = set([batch.name for batch in list(configured_project.batches())])
222-
assert names == set([batch_one, batch_two])
223+
assert names == set([batch_one, batch_two])
224+
225+
226+
def test_media_type(client, configured_project: Project, rand_gen):
227+
# Existing project with no media_type
228+
assert isinstance(configured_project.media_type, MediaType)
229+
230+
# Update test
231+
project = client.create_project(name=rand_gen(str))
232+
project.update(media_type=MediaType.Image)
233+
assert project.media_type == MediaType.Image
234+
project.delete()
235+
236+
for media_type in MediaType.get_supported_members():
237+
238+
project = client.create_project(name=rand_gen(str),
239+
media_type=MediaType[media_type])
240+
assert project.media_type == MediaType[media_type]
241+
project.delete()

0 commit comments

Comments
 (0)