2323import logging
2424import sys
2525import threading
26+ import time
2627from typing import (
2728 Any ,
2829 Callable ,
@@ -540,21 +541,25 @@ def _sync_gca_resource(self):
540541 @property
541542 def name (self ) -> str :
542543 """Name of this resource."""
544+ self ._assert_gca_resource_is_available ()
543545 return self ._gca_resource .name .split ("/" )[- 1 ]
544546
545547 @property
546548 def resource_name (self ) -> str :
547549 """Full qualified resource name."""
550+ self ._assert_gca_resource_is_available ()
548551 return self ._gca_resource .name
549552
550553 @property
551554 def display_name (self ) -> str :
552555 """Display name of this resource."""
556+ self ._assert_gca_resource_is_available ()
553557 return self ._gca_resource .display_name
554558
555559 @property
556560 def create_time (self ) -> datetime .datetime :
557561 """Time this resource was created."""
562+ self ._assert_gca_resource_is_available ()
558563 return self ._gca_resource .create_time
559564
560565 @property
@@ -570,6 +575,7 @@ def encryption_spec(self) -> Optional[gca_encryption_spec.EncryptionSpec]:
570575 If this is set, then all resources created by this Vertex AI resource will
571576 be encrypted with the provided encryption key.
572577 """
578+ self ._assert_gca_resource_is_available ()
573579 return getattr (self ._gca_resource , "encryption_spec" )
574580
575581 @property
@@ -578,13 +584,26 @@ def labels(self) -> Dict[str, str]:
578584
579585 Read more about labels at https://goo.gl/xmQnxf
580586 """
587+ self ._assert_gca_resource_is_available ()
581588 return self ._gca_resource .labels
582589
583590 @property
584591 def gca_resource (self ) -> proto .Message :
585592 """The underlying resource proto representation."""
593+ self ._assert_gca_resource_is_available ()
586594 return self ._gca_resource
587595
596+ def _assert_gca_resource_is_available (self ) -> None :
597+ """Helper method to raise when property is not accessible.
598+
599+ Raises:
600+ RuntimeError if _gca_resource is has not been created.
601+ """
602+ if self ._gca_resource is None :
603+ raise RuntimeError (
604+ f"{ self .__class__ .__name__ } resource has not been created"
605+ )
606+
588607 def __repr__ (self ) -> str :
589608 return f"{ object .__repr__ (self )} \n resource name: { self .resource_name } "
590609
@@ -1061,6 +1080,56 @@ def __repr__(self) -> str:
10611080
10621081 return FutureManager .__repr__ (self )
10631082
1083+ def _wait_for_resource_creation (self ) -> None :
1084+ """Wait until underlying resource is created.
1085+
1086+ Currently this should only be used on subclasses that implement the construct then
1087+ `run` pattern because the underlying sync=False implementation will not update
1088+ downstream resource noun object's _gca_resource until the entire invoked method is complete.
1089+
1090+ Ex:
1091+ job = CustomTrainingJob()
1092+ job.run(sync=False, ...)
1093+ job._wait_for_resource_creation()
1094+ Raises:
1095+ RuntimeError if the resource has not been scheduled to be created.
1096+ """
1097+
1098+ # If the user calls this but didn't actually invoke an API to create
1099+ if self ._are_futures_done () and not getattr (self ._gca_resource , "name" , None ):
1100+ self ._raise_future_exception ()
1101+ raise RuntimeError (
1102+ f"{ self .__class__ .__name__ } resource is not scheduled to be created."
1103+ )
1104+
1105+ while not getattr (self ._gca_resource , "name" , None ):
1106+ # breaks out of loop if creation has failed async
1107+ if self ._are_futures_done () and not getattr (
1108+ self ._gca_resource , "name" , None
1109+ ):
1110+ self ._raise_future_exception ()
1111+
1112+ time .sleep (1 )
1113+
1114+ def _assert_gca_resource_is_available (self ) -> None :
1115+ """Helper method to raise when accessing properties that do not exist.
1116+
1117+ Overrides VertexAiResourceNoun to provide a more informative exception if
1118+ resource creation has failed asynchronously.
1119+
1120+ Raises:
1121+ RuntimeError when resource has not been created.
1122+ """
1123+ if not getattr (self ._gca_resource , "name" , None ):
1124+ raise RuntimeError (
1125+ f"{ self .__class__ .__name__ } resource has not been created."
1126+ + (
1127+ f" Resource failed with: { self ._exception } "
1128+ if self ._exception
1129+ else ""
1130+ )
1131+ )
1132+
10641133
10651134def get_annotation_class (annotation : type ) -> type :
10661135 """Helper method to retrieve type annotation.
0 commit comments