@@ -28,6 +28,15 @@ class ErrorInfo(BaseModel):
2828 metadata (Dict[str, Any]): Additional dynamic information as context.
2929 """
3030
31+ # Constants for reason values
32+ REASON_TERMINATION_REASON = "TERMINATION_REASON"
33+ REASON_EXTRA_INFO = "EXTRA_INFO"
34+ REASON_ROLLOUT_ERROR = "ROLLOUT_ERROR"
35+ REASON_STOPPED = "STOPPED"
36+
37+ # Domain constant
38+ DOMAIN = "evalprotocol.io"
39+
3140 reason : str = Field (..., description = "Short snake_case description of the error cause" )
3241 domain : str = Field (..., description = "Logical grouping for the error reason" )
3342 metadata : Dict [str , Any ] = Field (default_factory = dict , description = "Additional dynamic information as context" )
@@ -42,24 +51,30 @@ def to_aip193_format(self) -> Dict[str, Any]:
4251 }
4352
4453 @classmethod
45- def termination_reason (cls , reason : str ) -> "ErrorInfo" :
54+ def termination_reason (cls , reason : Union [ str , TerminationReason ] ) -> "ErrorInfo" :
4655 """Create an ErrorInfo for termination reason."""
47- return cls (reason = "TERMINATION_REASON" , domain = "evalprotocol.io" , metadata = {"termination_reason" : reason })
56+ # Convert TerminationReason enum to string if needed
57+ reason_str = reason .value if isinstance (reason , TerminationReason ) else reason
58+ return cls (
59+ reason = cls .REASON_TERMINATION_REASON , domain = cls .DOMAIN , metadata = {"termination_reason" : reason_str }
60+ )
4861
4962 @classmethod
5063 def extra_info (cls , metadata : Dict [str , Any ]) -> "ErrorInfo" :
5164 """Create an ErrorInfo for extra information."""
52- return cls (reason = "EXTRA_INFO" , domain = "evalprotocol.io" , metadata = metadata )
65+ return cls (reason = cls . REASON_EXTRA_INFO , domain = cls . DOMAIN , metadata = metadata )
5366
5467 @classmethod
5568 def rollout_error (cls , metadata : Dict [str , Any ]) -> "ErrorInfo" :
5669 """Create an ErrorInfo for rollout errors."""
57- return cls (reason = "ROLLOUT_ERROR" , domain = "evalprotocol.io" , metadata = metadata )
70+ return cls (reason = cls . REASON_ROLLOUT_ERROR , domain = cls . DOMAIN , metadata = metadata )
5871
5972 @classmethod
60- def stopped_reason (cls , reason : str ) -> "ErrorInfo" :
73+ def stopped_reason (cls , reason : Union [ str , TerminationReason ] ) -> "ErrorInfo" :
6174 """Create an ErrorInfo for stopped reason."""
62- return cls (reason = "STOPPED" , domain = "evalprotocol.io" , metadata = {"reason" : reason })
75+ # Convert TerminationReason enum to string if needed
76+ reason_str = reason .value if isinstance (reason , TerminationReason ) else reason
77+ return cls (reason = cls .REASON_STOPPED , domain = cls .DOMAIN , metadata = {"reason" : reason_str })
6378
6479
6580class Status (BaseModel ):
@@ -116,7 +131,9 @@ def rollout_running(cls) -> "Status":
116131
117132 @classmethod
118133 def rollout_finished (
119- cls , termination_reason : Optional [str ] = None , extra_info : Optional [Dict [str , Any ]] = None
134+ cls ,
135+ termination_reason : Optional [Union [str , TerminationReason ]] = None ,
136+ extra_info : Optional [Dict [str , Any ]] = None ,
120137 ) -> "Status" :
121138 """Create a status indicating the rollout finished."""
122139 details = []
@@ -140,13 +157,15 @@ def error(cls, error_message: str, details: Optional[List[Dict[str, Any]]] = Non
140157 return cls (code = cls .Code .INTERNAL , message = error_message , details = details )
141158
142159 @classmethod
143- def rollout_stopped (cls , reason : str = "Rollout stopped" ) -> "Status" :
160+ def rollout_stopped (cls , reason : Union [ str , TerminationReason ] = "Rollout stopped" ) -> "Status" :
144161 """Create a status indicating the rollout was stopped."""
145162 details = [ErrorInfo .stopped_reason (reason ).to_aip193_format ()]
146163 return cls (code = cls .Code .CANCELLED , message = reason , details = details )
147164
148165 @classmethod
149- def with_termination_reason (cls , termination_reason : str , extra_info : Optional [Dict [str , Any ]] = None ) -> "Status" :
166+ def with_termination_reason (
167+ cls , termination_reason : Union [str , TerminationReason ], extra_info : Optional [Dict [str , Any ]] = None
168+ ) -> "Status" :
150169 """Create a status indicating the rollout finished with termination reason."""
151170 details = [ErrorInfo .termination_reason (termination_reason ).to_aip193_format ()]
152171
@@ -171,24 +190,26 @@ def is_stopped(self) -> bool:
171190 """Check if the status indicates the rollout was stopped."""
172191 return self .code == self .Code .CANCELLED
173192
174- def get_termination_reason (self ) -> Optional [str ]:
193+ def get_termination_reason (self ) -> Optional [TerminationReason ]:
175194 """Extract termination reason from details if present."""
176195 for detail in self .details :
177- if detail .get ("@type" ) == "type.googleapis.com/google.rpc.ErrorInfo" :
178- metadata = detail .get ("metadata" , {})
179- if detail .get ("reason" ) == "TERMINATION_REASON" and "termination_reason" in metadata :
180- return metadata ["termination_reason" ]
196+ metadata = detail .get ("metadata" , {})
197+ if detail .get ("reason" ) == ErrorInfo .REASON_TERMINATION_REASON and "termination_reason" in metadata :
198+ try :
199+ return TerminationReason .from_str (metadata ["termination_reason" ])
200+ except ValueError :
201+ # If the reason is not a valid enum value, return None
202+ return None
181203 return None
182204
183205 def get_extra_info (self ) -> Optional [Dict [str , Any ]]:
184206 """Extract extra info from details if present."""
185207 for detail in self .details :
186- if detail .get ("@type" ) == "type.googleapis.com/google.rpc.ErrorInfo" :
187- metadata = detail .get ("metadata" , {})
188- reason = detail .get ("reason" )
189- # Skip termination_reason and stopped details, return other error info
190- if reason not in ["TERMINATION_REASON" , "STOPPED" ]:
191- return metadata
208+ metadata = detail .get ("metadata" , {})
209+ reason = detail .get ("reason" )
210+ # Skip termination_reason and stopped details, return other error info
211+ if reason not in [ErrorInfo .REASON_TERMINATION_REASON , ErrorInfo .REASON_STOPPED ]:
212+ return metadata
192213 return None
193214
194215 def __hash__ (self ) -> int :
0 commit comments