@@ -620,6 +620,172 @@ def dropAllDepends(job, layer=None, frame=None):
620620 )
621621 depend .satisfy ()
622622
623+ @staticmethod
624+ def parseDependType (depend_type_str ):
625+ """Parse and validate dependency type string.
626+
627+ :type depend_type_str: str
628+ :param depend_type_str: String representation of dependency type
629+ :rtype: int
630+ :return: Dependency type enum value
631+ :raises: ValueError if type is invalid
632+ """
633+ depend_type_map = {
634+ 'JOB_ON_JOB' : opencue .api .depend_pb2 .JOB_ON_JOB ,
635+ 'JOB_ON_LAYER' : opencue .api .depend_pb2 .JOB_ON_LAYER ,
636+ 'JOB_ON_FRAME' : opencue .api .depend_pb2 .JOB_ON_FRAME ,
637+ 'LAYER_ON_JOB' : opencue .api .depend_pb2 .LAYER_ON_JOB ,
638+ 'LAYER_ON_LAYER' : opencue .api .depend_pb2 .LAYER_ON_LAYER ,
639+ 'LAYER_ON_FRAME' : opencue .api .depend_pb2 .LAYER_ON_FRAME ,
640+ 'FRAME_ON_JOB' : opencue .api .depend_pb2 .FRAME_ON_JOB ,
641+ 'FRAME_ON_LAYER' : opencue .api .depend_pb2 .FRAME_ON_LAYER ,
642+ 'FRAME_ON_FRAME' : opencue .api .depend_pb2 .FRAME_ON_FRAME ,
643+ 'FRAME_BY_FRAME' : opencue .api .depend_pb2 .FRAME_BY_FRAME ,
644+ 'LAYER_ON_SIM_FRAME' : opencue .api .depend_pb2 .LAYER_ON_SIM_FRAME ,
645+ }
646+
647+ depend_type_upper = depend_type_str .upper ()
648+ if depend_type_upper not in depend_type_map :
649+ raise ValueError ("Invalid dependency type: %s" % depend_type_str )
650+
651+ return depend_type_map [depend_type_upper ]
652+
653+ @staticmethod
654+ def createJobOnJobDepend (job_name , depend_on_job_name ):
655+ """Create a job-on-job dependency.
656+
657+ :type job_name: str
658+ :param job_name: Name of the job that will depend on another
659+ :type depend_on_job_name: str
660+ :param depend_on_job_name: Name of the job to depend on
661+ :rtype: opencue.wrappers.depend.Depend
662+ :return: The created dependency
663+ """
664+ job = opencue .api .findJob (job_name )
665+ depend_on_job = opencue .api .findJob (depend_on_job_name )
666+ logger .debug ("creating job-on-job depend: %s depends on %s" , job_name , depend_on_job_name )
667+ return job .createDependencyOnJob (depend_on_job )
668+
669+ @staticmethod
670+ def createLayerOnLayerDepend (job_name , layer_name , depend_on_job_name , depend_on_layer_name ):
671+ """Create a layer-on-layer dependency.
672+
673+ :type job_name: str
674+ :param job_name: Name of the job containing the dependent layer
675+ :type layer_name: str
676+ :param layer_name: Name of the layer that will depend on another
677+ :type depend_on_job_name: str
678+ :param depend_on_job_name: Name of the job containing the layer to depend on
679+ :type depend_on_layer_name: str
680+ :param depend_on_layer_name: Name of the layer to depend on
681+ :rtype: opencue.wrappers.depend.Depend
682+ :return: The created dependency
683+ """
684+ layer = opencue .api .findLayer (job_name , layer_name )
685+ depend_on_layer = opencue .api .findLayer (depend_on_job_name , depend_on_layer_name )
686+ logger .debug ("creating layer-on-layer depend: %s/%s depends on %s/%s" ,
687+ job_name , layer_name , depend_on_job_name , depend_on_layer_name )
688+ return layer .createDependencyOnLayer (depend_on_layer )
689+
690+ @staticmethod
691+ def createFrameByFrameDepend (job_name , layer_name , depend_on_job_name , depend_on_layer_name ):
692+ """Create a frame-by-frame dependency.
693+
694+ :type job_name: str
695+ :param job_name: Name of the job containing the dependent layer
696+ :type layer_name: str
697+ :param layer_name: Name of the layer that will depend frame-by-frame
698+ :type depend_on_job_name: str
699+ :param depend_on_job_name: Name of the job containing the layer to depend on
700+ :type depend_on_layer_name: str
701+ :param depend_on_layer_name: Name of the layer to depend on
702+ :rtype: opencue.wrappers.depend.Depend
703+ :return: The created dependency
704+ """
705+ layer = opencue .api .findLayer (job_name , layer_name )
706+ depend_on_layer = opencue .api .findLayer (depend_on_job_name , depend_on_layer_name )
707+ logger .debug ("creating frame-by-frame depend: %s/%s depends on %s/%s" ,
708+ job_name , layer_name , depend_on_job_name , depend_on_layer_name )
709+ return layer .createFrameByFrameDependency (depend_on_layer )
710+
711+ @staticmethod
712+ def checkDependSatisfaction (job_name , layer_name = None , frame_num = None ):
713+ """Check if all dependencies on the given object are satisfied.
714+
715+ :type job_name: str
716+ :param job_name: Name of the job
717+ :type layer_name: str
718+ :param layer_name: Optional name of the layer
719+ :type frame_num: int
720+ :param frame_num: Optional frame number
721+ :rtype: bool
722+ :return: True if all dependencies are satisfied, False otherwise
723+ """
724+ if frame_num is not None :
725+ obj = opencue .api .findFrame (job_name , layer_name , frame_num )
726+ elif layer_name :
727+ obj = opencue .api .findLayer (job_name , layer_name )
728+ else :
729+ obj = opencue .api .findJob (job_name )
730+
731+ depends = obj .getWhatThisDependsOn ()
732+ for depend in depends :
733+ if not depend .data .active :
734+ continue
735+ # A dependency is not satisfied if it's still active
736+ return False
737+ return True
738+
739+ @staticmethod
740+ def detectCircularDepend (job_name , depend_on_job_name ):
741+ """Detect if creating a dependency would create a circular dependency.
742+
743+ :type job_name: str
744+ :param job_name: Name of the job that will depend on another
745+ :type depend_on_job_name: str
746+ :param depend_on_job_name: Name of the job to depend on
747+ :rtype: bool
748+ :return: True if circular dependency detected, False otherwise
749+ """
750+ if job_name == depend_on_job_name :
751+ return True
752+
753+ try :
754+ job = opencue .api .findJob (job_name )
755+ depend_on_job = opencue .api .findJob (depend_on_job_name )
756+
757+ # Check if depend_on_job already depends on job (would create a cycle)
758+ depends = depend_on_job .getWhatThisDependsOn ()
759+ for depend in depends :
760+ # Check if any dependency points back to our job
761+ if (hasattr (depend .data , 'depend_on_job' ) and
762+ depend .data .depend_on_job == job .data .id ):
763+ return True
764+ # For deeper circular dependency detection, we'd need to traverse the full graph
765+ # This is a simplified check for direct circular dependencies
766+
767+ return False
768+ except Exception :
769+ # If we can't find the jobs, we can't detect circularity
770+ return False
771+
772+ @staticmethod
773+ def formatDependStatus (depend ):
774+ """Format dependency status for display.
775+
776+ :type depend: opencue.wrappers.depend.Depend
777+ :param depend: The dependency to format
778+ :rtype: str
779+ :return: Formatted string representing the dependency status
780+ """
781+ depend_type = str (depend .data .type )
782+ active_status = "ACTIVE" if depend .data .active else "SATISFIED"
783+
784+ # Extract the dependency type name from the enum
785+ type_name = depend_type .rsplit ('.' , maxsplit = 1 )[- 1 ] if '.' in depend_type else depend_type
786+
787+ return "%s [%s]" % (type_name , active_status )
788+
623789
624790class Convert (object ):
625791 """Utility class for converting between units."""
0 commit comments