11import datetime
2- from typing import TYPE_CHECKING
2+ from typing import TYPE_CHECKING , Union , List
33import yaml
44from pathlib import Path
55import logging
66
77from labelbox .alignerr .schema .project_rate import BillingMode
8+ from labelbox .alignerr .schema .enchanced_resource_tags import ResourceTagType
89from labelbox .schema .media_type import MediaType
910
1011logger = logging .getLogger (__name__ )
@@ -18,21 +19,43 @@ class AlignerrProjectFactory:
1819 def __init__ (self , client : "Client" ):
1920 self .client = client
2021
21- def create (self , yaml_file_path : str , skip_validation : bool = False ):
22+ def create (self , yaml_file_path : str , skip_validation : Union [ bool , List ] = False ):
2223 """
2324 Create an AlignerrProject from a YAML configuration file.
2425
2526 Args:
2627 yaml_file_path: Path to the YAML configuration file
27- skip_validation: Whether to skip validation of required fields
28+ skip_validation: Whether to skip validation of required fields. Can be:
29+ - bool: Skip all validations (True) or run all validations (False)
30+ - List: Skip specific validations (e.g., [ValidationType.PROJECT_OWNER])
2831
2932 Returns:
30- AlignerrProject: The created project with configured rates
33+ AlignerrProject: The created project with all configured attributes
3134
3235 Raises:
3336 FileNotFoundError: If the YAML file doesn't exist
3437 yaml.YAMLError: If the YAML file is invalid
3538 ValueError: If required fields are missing or invalid
39+
40+ YAML Configuration Structure:
41+ name: str (required) - Project name
42+ media_type: str (required) - Media type (e.g., "Image", "Video", "Text")
43+ rates: dict (optional) - Alignerr role rates
44+ role_name:
45+ rate: float
46+ billing_mode: str
47+ effective_since: str (ISO datetime)
48+ effective_until: str (optional, ISO datetime)
49+ customer_rate: dict (optional) - Customer billing rate
50+ rate: float
51+ billing_mode: str
52+ effective_since: str (ISO datetime)
53+ effective_until: str (optional, ISO datetime)
54+ domains: list[str] (optional) - Project domain names
55+ tags: list[dict] (optional) - Enhanced resource tags
56+ - text: str
57+ type: str (ResourceTagType enum value)
58+ project_owner: str (optional) - Project owner email address
3659 """
3760 logger .info (f"Creating project from YAML file: { yaml_file_path } " )
3861
@@ -150,5 +173,110 @@ def create(self, yaml_file_path: str, skip_validation: bool = False):
150173 effective_until = effective_until ,
151174 )
152175
176+ # Set customer rate if provided
177+ if "customer_rate" in config :
178+ customer_rate_config = config ["customer_rate" ]
179+ if not isinstance (customer_rate_config , dict ):
180+ raise ValueError ("'customer_rate' must be a dictionary" )
181+
182+ # Validate customer rate configuration
183+ required_customer_rate_fields = [
184+ "rate" ,
185+ "billing_mode" ,
186+ "effective_since" ,
187+ ]
188+ for field in required_customer_rate_fields :
189+ if field not in customer_rate_config :
190+ raise ValueError (
191+ f"Required field '{ field } ' is missing for customer_rate"
192+ )
193+
194+ # Parse billing mode
195+ try :
196+ billing_mode = BillingMode (customer_rate_config ["billing_mode" ])
197+ except ValueError :
198+ raise ValueError (
199+ f"Invalid billing_mode '{ customer_rate_config ['billing_mode' ]} ' for customer_rate. Must be one of: { [e .value for e in BillingMode ]} "
200+ )
201+
202+ # Parse effective dates
203+ try :
204+ effective_since = datetime .datetime .fromisoformat (
205+ customer_rate_config ["effective_since" ]
206+ )
207+ except ValueError :
208+ raise ValueError (
209+ f"Invalid effective_since date format for customer_rate. Use ISO format (YYYY-MM-DDTHH:MM:SS)"
210+ )
211+
212+ effective_until = None
213+ if (
214+ "effective_until" in customer_rate_config
215+ and customer_rate_config ["effective_until" ]
216+ ):
217+ try :
218+ effective_until = datetime .datetime .fromisoformat (
219+ customer_rate_config ["effective_until" ]
220+ )
221+ except ValueError :
222+ raise ValueError (
223+ f"Invalid effective_until date format for customer_rate. Use ISO format (YYYY-MM-DDTHH:MM:SS)"
224+ )
225+
226+ # Set the customer rate
227+ builder .set_customer_rate (
228+ rate = float (customer_rate_config ["rate" ]),
229+ billing_mode = billing_mode ,
230+ effective_since = effective_since ,
231+ effective_until = effective_until ,
232+ )
233+
234+ # Set domains if provided
235+ if "domains" in config :
236+ domains_config = config ["domains" ]
237+ if not isinstance (domains_config , list ):
238+ raise ValueError ("'domains' must be a list" )
239+
240+ if not all (isinstance (domain , str ) for domain in domains_config ):
241+ raise ValueError ("All domain names must be strings" )
242+
243+ builder .set_domains (domains_config )
244+
245+ # Set enhanced resource tags if provided
246+ if "tags" in config :
247+ tags_config = config ["tags" ]
248+ if not isinstance (tags_config , list ):
249+ raise ValueError ("'tags' must be a list" )
250+
251+ for tag_config in tags_config :
252+ if not isinstance (tag_config , dict ):
253+ raise ValueError ("Each tag must be a dictionary" )
254+
255+ required_tag_fields = ["text" , "type" ]
256+ for field in required_tag_fields :
257+ if field not in tag_config :
258+ raise ValueError (
259+ f"Required field '{ field } ' is missing for tag"
260+ )
261+
262+ # Validate tag type
263+ try :
264+ tag_type = ResourceTagType (tag_config ["type" ])
265+ except ValueError :
266+ raise ValueError (
267+ f"Invalid tag type '{ tag_config ['type' ]} '. Must be one of: { [e .value for e in ResourceTagType ]} "
268+ )
269+
270+ # Set the tag
271+ builder .set_tags ([tag_config ["text" ]], tag_type )
272+
273+ # Set project owner if provided
274+ if "project_owner" in config :
275+ project_owner_config = config ["project_owner" ]
276+ if not isinstance (project_owner_config , str ):
277+ raise ValueError ("'project_owner' must be a string (email address)" )
278+
279+ builder .set_project_owner (project_owner_config )
280+
153281 # Create the project
154282 return builder .create (skip_validation = skip_validation )
0 commit comments