Skip to content

Commit bf6f3c3

Browse files
authored
Worfklow - Fix and updates following review (#1987)
1 parent a56501f commit bf6f3c3

18 files changed

+464
-269
lines changed

libs/labelbox/src/labelbox/schema/workflow/__init__.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,18 @@
3939
from labelbox.schema.workflow.graph import ProjectWorkflowGraph
4040

4141
# Import from monolithic workflow.py file
42-
from labelbox.schema.workflow.workflow import ProjectWorkflow, NodeType
42+
from labelbox.schema.workflow.workflow import (
43+
ProjectWorkflow,
44+
NodeType,
45+
InitialNodes,
46+
)
47+
48+
# Import configuration classes
49+
from labelbox.schema.workflow.config import LabelingConfig, ReworkConfig
4350

4451
# Import from monolithic project_filter.py file
4552
from labelbox.schema.workflow.project_filter import (
4653
ProjectWorkflowFilter,
47-
created_by,
4854
labeled_by,
4955
annotation,
5056
dataset,
@@ -94,13 +100,17 @@
94100
"NodeType",
95101
"ProjectWorkflowGraph",
96102
"ProjectWorkflowFilter",
97-
# Filter construction functions
98-
"created_by",
103+
# Workflow configuration
104+
"InitialNodes",
105+
"LabelingConfig",
106+
"ReworkConfig",
107+
# Filter field objects
99108
"labeled_by",
100109
"annotation",
101-
"sample",
102110
"dataset",
103111
"issue_category",
112+
# Filter construction functions
113+
"sample",
104114
"model_prediction",
105115
"natural_language",
106116
"labeled_at",
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""Configuration models for workflow initial nodes."""
2+
3+
from typing import Optional, Union, List
4+
from pydantic import BaseModel, Field
5+
6+
7+
class LabelingConfig(BaseModel):
8+
"""Configuration for InitialLabeling node creation.
9+
10+
Attributes:
11+
instructions: Task instructions for labelers
12+
max_contributions_per_user: Maximum contributions per user (null means infinite)
13+
"""
14+
15+
instructions: Optional[str] = Field(
16+
default=None, description="Task instructions for labelers"
17+
)
18+
max_contributions_per_user: Optional[int] = Field(
19+
default=None,
20+
description="Maximum contributions per user (null means infinite)",
21+
ge=0,
22+
)
23+
24+
25+
class ReworkConfig(BaseModel):
26+
"""Configuration for InitialRework node creation.
27+
28+
Attributes:
29+
instructions: Task instructions for rework
30+
individual_assignment: User IDs for individual assignment
31+
max_contributions_per_user: Maximum contributions per user (null means infinite)
32+
"""
33+
34+
instructions: Optional[str] = Field(
35+
default=None, description="Task instructions for rework"
36+
)
37+
individual_assignment: Optional[Union[str, List[str]]] = Field(
38+
default=None, description="User IDs for individual assignment"
39+
)
40+
max_contributions_per_user: Optional[int] = Field(
41+
default=None,
42+
description="Maximum contributions per user (null means infinite)",
43+
ge=0,
44+
)

libs/labelbox/src/labelbox/schema/workflow/enums.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class FilterField(str, Enum):
106106
"""
107107

108108
# User and creation filters
109-
CreatedBy = "CreatedBy"
109+
LabeledBy = "CreatedBy" # Maps to backend CreatedBy field
110110

111111
# Annotation and content filters
112112
Annotation = "Annotation"

libs/labelbox/src/labelbox/schema/workflow/nodes/autoqa_node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class AutoQANode(BaseWorkflowNode):
7979
The evaluation results determine automatic routing without human intervention.
8080
"""
8181

82-
label: str = Field(default="Label Score (AutoQA)")
82+
label: str = Field(default="Label Score (AutoQA)", max_length=50)
8383
filters: List[Dict[str, Any]] = Field(
8484
default_factory=lambda: [],
8585
description="Contains the filters for the AutoQA node",

libs/labelbox/src/labelbox/schema/workflow/nodes/custom_rework_node.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class CustomReworkNode(BaseWorkflowNode):
8181
rework processes and quality checks.
8282
"""
8383

84-
label: str = Field(default="")
84+
label: str = Field(default="", max_length=50)
8585
node_config: List[ConfigEntry] = Field(
8686
default_factory=lambda: [],
8787
description="Contains assignment rules etc.",
@@ -117,6 +117,7 @@ class CustomReworkNode(BaseWorkflowNode):
117117
default=None,
118118
description="Maximum contributions per user (null means infinite)",
119119
alias="maxContributionsPerUser",
120+
ge=0,
120121
)
121122
# Has one input and one output
122123
output_else: None = Field(default=None, frozen=True) # Only one output (if)

libs/labelbox/src/labelbox/schema/workflow/nodes/done_node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class DoneNode(BaseWorkflowNode):
5757
and will not flow to any other nodes in the workflow.
5858
"""
5959

60-
label: str = Field(default="Done")
60+
label: str = Field(default="Done", max_length=50)
6161
definition_id: WorkflowDefinitionId = Field(
6262
default=WorkflowDefinitionId.Done, frozen=True, alias="definitionId"
6363
)

libs/labelbox/src/labelbox/schema/workflow/nodes/initial_labeling_node.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ class InitialLabelingNode(BaseWorkflowNode):
5959
and cannot have incoming connections from other nodes.
6060
"""
6161

62-
label: str = Field(default="Initial labeling task", frozen=True)
62+
label: str = Field(
63+
default="Initial labeling task", frozen=True, max_length=50
64+
)
6365
filter_logic: Literal["and", "or"] = Field(
6466
default=DEFAULT_FILTER_LOGIC_AND, alias="filterLogic"
6567
)
@@ -84,6 +86,7 @@ class InitialLabelingNode(BaseWorkflowNode):
8486
default=None,
8587
description="Maximum contributions per user (null means infinite)",
8688
alias="maxContributionsPerUser",
89+
ge=0,
8790
)
8891
node_config: List[ConfigEntry] = Field(
8992
default_factory=lambda: [],

libs/labelbox/src/labelbox/schema/workflow/nodes/initial_rework_node.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ class InitialReworkNode(BaseWorkflowNode):
6666
to ensure proper routing in the Labelbox platform.
6767
"""
6868

69-
label: str = Field(default="Rework (all rejected)", frozen=True)
69+
label: str = Field(
70+
default="Rework (all rejected)", frozen=True, max_length=50
71+
)
7072
filter_logic: Literal["and", "or"] = Field(
7173
default=DEFAULT_FILTER_LOGIC_AND, alias="filterLogic"
7274
)
@@ -100,6 +102,7 @@ class InitialReworkNode(BaseWorkflowNode):
100102
default=None,
101103
description="Maximum contributions per user (null means infinite)",
102104
alias="maxContributionsPerUser",
105+
ge=0,
103106
)
104107

105108
@field_validator("individual_assignment", mode="before")

libs/labelbox/src/labelbox/schema/workflow/nodes/logic_node.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ class LogicNode(BaseWorkflowNode):
3030
"""Logic node. One or more instances possible. One input, two outputs (if/else)."""
3131

3232
label: str = Field(
33-
default="Logic", description="Display name for the logic node"
33+
default="Logic",
34+
description="Display name for the logic node",
35+
max_length=50,
3436
)
3537
filters: List[Dict[str, Any]] = Field(
3638
default_factory=lambda: [],
@@ -199,7 +201,7 @@ def remove_filter(self, filter_field: FilterField) -> "LogicNode":
199201
200202
Args:
201203
filter_field: FilterField enum value specifying which filter type to remove
202-
(e.g., FilterField.CreatedBy, FilterField.Sample, FilterField.LabelingTime)
204+
(e.g., FilterField.LabeledBy, FilterField.Sample, FilterField.LabelingTime)
203205
204206
Returns:
205207
LogicNode: Self for method chaining
@@ -209,7 +211,7 @@ def remove_filter(self, filter_field: FilterField) -> "LogicNode":
209211
>>>
210212
>>> # Type-safe enum approach (required)
211213
>>> logic.remove_filter(FilterField.Sample)
212-
>>> logic.remove_filter(FilterField.CreatedBy)
214+
>>> logic.remove_filter(FilterField.LabeledBy) # Consistent with labeled_by() function
213215
>>> logic.remove_filter(FilterField.LabelingTime)
214216
>>> logic.remove_filter(FilterField.Metadata)
215217
"""
@@ -371,7 +373,7 @@ def get_filters(self) -> "ProjectWorkflowFilter":
371373
>>> logic = workflow.get_node_by_id("some-logic-node-id")
372374
>>> user_filters = logic.get_filters()
373375
>>> # Add a new filter
374-
>>> user_filters.append(created_by(["new-user-id"]))
376+
>>> user_filters.append(labeled_by(["new-user-id"]))
375377
>>> # Apply the updated filters back to the node
376378
>>> logic.set_filters(user_filters)
377379
"""
@@ -393,25 +395,25 @@ def add_filter(self, filter_rule: Dict[str, Any]) -> "LogicNode":
393395
394396
Args:
395397
filter_rule: Filter rule from filter functions
396-
(e.g., created_by(["user_id"]), labeling_time.greater_than(300))
398+
(e.g., labeled_by(["user_id"]), labeling_time.greater_than(300))
397399
398400
Returns:
399401
LogicNode: Self for method chaining
400402
401403
Example:
402-
>>> from labelbox.schema.workflow.project_filter import created_by, labeling_time, metadata, condition
404+
>>> from labelbox.schema.workflow.project_filter import labeled_by, labeling_time, metadata, condition
403405
>>>
404-
>>> logic.add_filter(created_by(["user-123"]))
406+
>>> logic.add_filter(labeled_by(["user-123"]))
405407
>>> logic.add_filter(labeling_time.greater_than(300))
406408
>>> logic.add_filter(metadata([condition.contains("tag", "test")]))
407-
>>> # Adding another created_by filter will replace the previous one
408-
>>> logic.add_filter(created_by(["user-456"])) # Replaces previous created_by filter
409+
>>> # Adding another labeled_by filter will replace the previous one
410+
>>> logic.add_filter(labeled_by(["user-456"])) # Replaces previous labeled_by filter
409411
"""
410412
# Validate that this looks like filter function output
411413
if not self._is_filter_function_output(filter_rule):
412414
raise ValueError(
413415
"add_filter() only accepts output from filter functions. "
414-
"Use functions like created_by(), labeling_time.greater_than(), etc."
416+
"Use functions like labeled_by(), labeling_time.greater_than(), etc."
415417
)
416418

417419
# Get the field name from the filter rule to check for existing filters
@@ -455,7 +457,7 @@ def _is_filter_function_output(self, filter_rule: Dict[str, Any]) -> bool:
455457

456458
# Map backend field names to FilterField enum values
457459
backend_to_field = {
458-
"CreatedBy": FilterField.CreatedBy,
460+
"CreatedBy": FilterField.LabeledBy, # Backend CreatedBy maps to user-facing LabeledBy
459461
"Annotation": FilterField.Annotation,
460462
"LabeledAt": FilterField.LabeledAt,
461463
"Sample": FilterField.Sample,

libs/labelbox/src/labelbox/schema/workflow/nodes/review_node.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class ReviewNode(BaseWorkflowNode):
6969
which default to "and" logic. This allows more flexible routing.
7070
"""
7171

72-
label: str = Field(default="Review task")
72+
label: str = Field(default="Review task", max_length=50)
7373
# For ReviewNode, filter_logic defaults to "or"
7474
filter_logic: Literal["and", "or"] = Field(
7575
default=DEFAULT_FILTER_LOGIC_OR, alias="filterLogic"
@@ -96,6 +96,7 @@ class ReviewNode(BaseWorkflowNode):
9696
default=None,
9797
description="Maximum contributions per user (null means infinite)",
9898
alias="maxContributionsPerUser",
99+
ge=0,
99100
)
100101
node_config: List[Dict[str, Any]] = Field(
101102
default_factory=lambda: [],

libs/labelbox/src/labelbox/schema/workflow/nodes/rework_node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class ReworkNode(BaseWorkflowNode):
6161
workflow's initial rework entry point without manual routing.
6262
"""
6363

64-
label: str = Field(default="Rework")
64+
label: str = Field(default="Rework", max_length=50)
6565
filter_logic: Literal["and", "or"] = Field(
6666
default=DEFAULT_FILTER_LOGIC_AND, alias="filterLogic"
6767
)

libs/labelbox/src/labelbox/schema/workflow/nodes/unknown_workflow_node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class UnknownWorkflowNode(BaseWorkflowNode):
7171
as a safety mechanism to prevent data loss during parsing.
7272
"""
7373

74-
label: str = Field(default="")
74+
label: str = Field(default="", max_length=50)
7575
node_config: Optional[List[Dict[str, Any]]] = Field(
7676
default=None, alias="config"
7777
)

0 commit comments

Comments
 (0)