@@ -527,12 +527,14 @@ class VersionRequirement(interfaces.configuration.RequirementInterface):
527527 def __init__ (
528528 self ,
529529 name : str ,
530- description : str = None ,
530+ description : Optional [ str ] = None ,
531531 default : bool = False ,
532532 optional : bool = False ,
533533 component : Type [interfaces .configuration .VersionableInterface ] = None ,
534534 version : Optional [Tuple [int , ...]] = None ,
535535 ) -> None :
536+ if description is None :
537+ description = f"Version { '.' .join ([str (x ) for x in version ])} dependency on { component .__module__ } .{ component .__name__ } unmet"
536538 super ().__init__ (
537539 name = name , description = description , default = default , optional = optional
538540 )
@@ -544,15 +546,51 @@ def __init__(
544546 self ._version = version
545547
546548 def unsatisfied (
547- self , context : interfaces .context .ContextInterface , config_path : str
549+ self ,
550+ context : interfaces .context .ContextInterface ,
551+ config_path : str ,
552+ accumulator : Optional [
553+ List [interfaces .configuration .VersionableInterface ]
554+ ] = None ,
548555 ) -> Dict [str , interfaces .configuration .RequirementInterface ]:
549556 # Mypy doesn't appreciate our classproperty implementation, self._plugin.version has no type
550557 config_path = interfaces .configuration .path_join (config_path , self .name )
551558 if not self .matches_required (self ._version , self ._component .version ):
552559 return {config_path : self }
560+
561+ recurse = True
562+ if accumulator is None :
563+ accumulator = set ([self ._component ])
564+ else :
565+ if self ._component in accumulator :
566+ recurse = False
567+ else :
568+ accumulator .add (self ._component )
569+
570+ # Check for child requirements
571+ if (
572+ issubclass (self ._component , interfaces .configuration .ConfigurableInterface )
573+ and recurse
574+ ):
575+ result = {}
576+ for requirement in self ._component .get_requirements ():
577+ if not requirement .optional and isinstance (
578+ requirement , VersionRequirement
579+ ):
580+ result .update (
581+ requirement .unsatisfied (
582+ context , config_path , accumulator .copy ()
583+ )
584+ )
585+
586+ if result :
587+ result .update ({config_path : self })
588+ return result
589+
553590 context .config [interfaces .configuration .path_join (config_path , self .name )] = (
554591 True
555592 )
593+
556594 return {}
557595
558596 @classmethod
0 commit comments