Skip to content

Commit d4ae2ef

Browse files
[ALNR-6808] Remove ProjectRateV2 methods from lbox-alignerr SDK
Delete legacy Pay By Role rate helpers and fail clearly pointing callers to the Rates UI (Pay By Activity). Bump package to 0.3.0.
1 parent c8ac7fb commit d4ae2ef

11 files changed

Lines changed: 103 additions & 815 deletions

libs/lbox-alignerr/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@ Alignerr workspace management for Labelbox.
44

55
This package provides functionality for managing Alignerr projects, including:
66
- Project creation and configuration
7-
- Rate management for labelers and reviewers
87
- Domain and tag management
98
- Workforce management

libs/lbox-alignerr/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "lbox-alignerr"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
description = "Alignerr workspace management for Labelbox"
55
authors = [
66
{ name = "Labelbox", email = "engineering@labelbox.com" }

libs/lbox-alignerr/src/alignerr/alignerr_project.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import logging
55

6-
from alignerr.schema.project_rate import ProjectRateV2
76
from alignerr.schema.project_domain import ProjectDomain
87
from alignerr.schema.enchanced_resource_tags import (
98
EnhancedResourceTag,
@@ -17,6 +16,11 @@
1716

1817
logger = logging.getLogger(__name__)
1918

19+
PAY_BY_ROLE_REMOVED_MSG = (
20+
"Pay By Role rates were removed. "
21+
"Configure project rates in the Labelbox Rates UI (Pay By Activity)."
22+
)
23+
2024

2125
if TYPE_CHECKING:
2226
from labelbox import Client
@@ -63,17 +67,11 @@ def add_domain(self, project_domain: ProjectDomain):
6367
domain_ids=[project_domain.uid],
6468
)
6569

66-
def get_project_rates(self) -> list["ProjectRateV2"]:
67-
return ProjectRateV2.get_by_project_id(
68-
client=self.client, project_id=self.project.uid
69-
)
70+
def get_project_rates(self, *args, **kwargs):
71+
raise NotImplementedError(PAY_BY_ROLE_REMOVED_MSG)
7072

71-
def set_project_rate(self, project_rate_input):
72-
return ProjectRateV2.set_project_rate(
73-
client=self.client,
74-
project_id=self.project.uid,
75-
project_rate_input=project_rate_input,
76-
)
73+
def set_project_rate(self, *args, **kwargs):
74+
raise NotImplementedError(PAY_BY_ROLE_REMOVED_MSG)
7775

7876
def set_tags(self, tag_names: list[str], tag_type: ResourceTagType):
7977
# Convert tag names to tag IDs

libs/lbox-alignerr/src/alignerr/alignerr_project_builder.py

Lines changed: 8 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import datetime
21
from enum import Enum
32
from typing import TYPE_CHECKING, Optional, Union, List
43
import logging
54

6-
from alignerr.schema.project_rate import BillingMode
7-
from alignerr.schema.project_rate import ProjectRateInput
5+
from alignerr.alignerr_project import PAY_BY_ROLE_REMOVED_MSG
86
from alignerr.schema.project_domain import ProjectDomain
97
from alignerr.schema.enchanced_resource_tags import (
108
EnhancedResourceTag,
@@ -28,18 +26,15 @@ class ValidationType(Enum):
2826

2927
if TYPE_CHECKING:
3028
from labelbox import Client
31-
from alignerr.alignerr_project import AlignerrProject, AlignerrRole
29+
from alignerr.alignerr_project import AlignerrProject
3230

3331

3432
class AlignerrProjectBuilder:
3533
def __init__(self, client: "Client"):
3634
self.client = client
37-
self._alignerr_rates: dict[str, ProjectRateInput] = {}
38-
self._customer_rate: Optional[ProjectRateInput] = None
3935
self._domains: list[ProjectDomain] = []
4036
self._enhanced_resource_tags: list[EnhancedResourceTag] = []
4137
self._project_owner_email: Optional[str] = None
42-
self.role_name_to_id = self._get_role_name_to_id()
4338

4439
def set_name(self, name: str):
4540
self.project_name = name
@@ -49,72 +44,11 @@ def set_media_type(self, media_type: "MediaType"):
4944
self.project_media_type = media_type
5045
return self
5146

52-
def set_alignerr_role_rate(
53-
self,
54-
*,
55-
role_name: "AlignerrRole",
56-
rate: float,
57-
billing_mode: BillingMode,
58-
effective_since: datetime.datetime,
59-
effective_until: Optional[datetime.datetime] = None,
60-
):
61-
if role_name.value not in self.role_name_to_id:
62-
raise ValueError(f"Role {role_name.value} not found")
63-
64-
role_id = self.role_name_to_id[role_name.value]
65-
role_name_str = role_name.value
66-
67-
# Convert datetime objects to ISO format strings
68-
effective_since_str = (
69-
effective_since.isoformat()
70-
if isinstance(effective_since, datetime.datetime)
71-
else effective_since
72-
)
73-
effective_until_str = (
74-
effective_until.isoformat()
75-
if isinstance(effective_until, datetime.datetime)
76-
else effective_until
77-
)
78-
79-
self._alignerr_rates[role_name_str] = ProjectRateInput(
80-
rateForId=role_id,
81-
isBillRate=False,
82-
billingMode=billing_mode,
83-
rate=rate,
84-
effectiveSince=effective_since_str,
85-
effectiveUntil=effective_until_str,
86-
)
87-
return self
47+
def set_alignerr_role_rate(self, *args, **kwargs):
48+
raise NotImplementedError(PAY_BY_ROLE_REMOVED_MSG)
8849

89-
def set_customer_rate(
90-
self,
91-
*,
92-
rate: float,
93-
billing_mode: BillingMode,
94-
effective_since: datetime.datetime,
95-
effective_until: Optional[datetime.datetime] = None,
96-
):
97-
# Convert datetime objects to ISO format strings
98-
effective_since_str = (
99-
effective_since.isoformat()
100-
if isinstance(effective_since, datetime.datetime)
101-
else effective_since
102-
)
103-
effective_until_str = (
104-
effective_until.isoformat()
105-
if isinstance(effective_until, datetime.datetime)
106-
else effective_until
107-
)
108-
109-
self._customer_rate = ProjectRateInput(
110-
rateForId="", # Empty string for customer rate
111-
isBillRate=True,
112-
billingMode=billing_mode,
113-
rate=rate,
114-
effectiveSince=effective_since_str,
115-
effectiveUntil=effective_until_str,
116-
)
117-
return self
50+
def set_customer_rate(self, *args, **kwargs):
51+
raise NotImplementedError(PAY_BY_ROLE_REMOVED_MSG)
11852

11953
def set_domains(self, domains: list[str]):
12054
for domain in domains:
@@ -189,18 +123,12 @@ def create(self, skip_validation: Union[bool, List[ValidationType]] = False):
189123
self.client, labelbox_project, _internal=True
190124
)
191125

192-
self._create_rates(alignerr_project)
193126
self._create_domains(alignerr_project)
194127
self._create_resource_tags(alignerr_project)
195128
self._create_project_owner(alignerr_project)
196129

197130
return alignerr_project
198131

199-
def _create_rates(self, alignerr_project: "AlignerrProject"):
200-
for alignerr_role, project_rate in self._alignerr_rates.items():
201-
logger.info(f"Setting project rate for {alignerr_role}")
202-
alignerr_project.set_project_rate(project_rate)
203-
204132
def _create_domains(self, alignerr_project: "AlignerrProject"):
205133
if self._domains:
206134
logger.info(f"Setting domains: {[domain.name for domain in self._domains]}")
@@ -248,30 +176,11 @@ def _create_project_owner(self, alignerr_project: "AlignerrProject"):
248176
project_owner_user_id=user_id,
249177
)
250178

251-
def _validate_alignerr_rates(self):
252-
# Import here to avoid circular imports
253-
from alignerr.alignerr_project import AlignerrRole
254-
255-
required_role_rates = set(
256-
[AlignerrRole.Labeler.value, AlignerrRole.Reviewer.value]
257-
)
258-
259-
for role_name in self._alignerr_rates.keys():
260-
required_role_rates.remove(role_name)
261-
if len(required_role_rates) > 0:
262-
raise ValueError(f"Required role rates are not set: {required_role_rates}")
263-
264-
def _validate_customer_rate(self):
265-
if self._customer_rate is None:
266-
raise ValueError("Customer rate is not set")
267-
268179
def _validate_project_owner(self):
269180
if self._project_owner_email is None:
270181
raise ValueError("Project owner is not set")
271182

272183
def _validate(self):
273-
self._validate_alignerr_rates()
274-
self._validate_customer_rate()
275184
self._validate_project_owner()
276185

277186
def _validate_selective(self, skip_validations: List[ValidationType]):
@@ -280,19 +189,11 @@ def _validate_selective(self, skip_validations: List[ValidationType]):
280189
Args:
281190
skip_validations: List of ValidationType enums to skip
282191
"""
283-
if ValidationType.ALIGNERR_RATE not in skip_validations:
284-
self._validate_alignerr_rates()
285-
286-
if ValidationType.CUSTOMER_RATE not in skip_validations:
287-
self._validate_customer_rate()
288-
192+
# ALIGNERR_RATE / CUSTOMER_RATE are retained for callers that still pass them
193+
# in skip_validation lists; rate validation itself has been removed.
289194
if ValidationType.PROJECT_OWNER not in skip_validations:
290195
self._validate_project_owner()
291196

292-
def _get_role_name_to_id(self) -> dict[str, str]:
293-
roles = self.client.get_roles()
294-
return {role.name: role.uid for role in roles.values()}
295-
296197
def _find_user_by_email(self, email: str) -> Optional[str]:
297198
"""Find user ID by email in the organization.
298199

0 commit comments

Comments
 (0)