@@ -254,6 +254,47 @@ def __repr__(self):
254254 "" .join (steps ),
255255 )
256256
257+ def validate (
258+ self , inputs : Optional [abc .Collection ], outputs : Optional [abc .Collection ]
259+ ):
260+ """
261+ Scream on invalid inputs, outputs or no operations in graph.
262+
263+ :raises ValueError:
264+ - If given `inputs` mismatched :attr:`needs`, with msg:
265+
266+ *Plan needs more inputs...*
267+ - If `outputs` asked cannot be produced by the :attr:`dag`, with msg:
268+
269+ *Impossible outputs...*
270+
271+ - If cannot produce any `outputs` from the given `inputs`, with msg:
272+
273+ *Unsolvable graph: ...*
274+ """
275+ if not self .dag :
276+ raise ValueError (f"Unsolvable graph:\n { self } " )
277+
278+ # Check plan<-->inputs mismatch.
279+ #
280+ missing = iset (self .needs ) - set (inputs )
281+ if missing :
282+ raise ValueError (
283+ f"Plan needs more inputs: { list (missing )} "
284+ f"\n given inputs: { list (inputs )} \n { self } "
285+ )
286+
287+ if outputs :
288+ unknown = (
289+ iset (astuple (outputs , "outputs" , allowed_types = abc .Sequence ))
290+ - self .provides
291+ )
292+ if unknown :
293+ raise ValueError (
294+ f"Impossible outputs: { list (unknown )} \n for graph: { self } "
295+ f"\n { self } "
296+ )
297+
257298 def _pin_data_in_solution (self , value_name , solution , inputs , overwrites ):
258299 value_name = str (value_name )
259300 if overwrites is not None :
@@ -425,28 +466,7 @@ def execute(self, named_inputs, outputs=None, *, overwrites=None, method=None):
425466 *Unsolvable graph: ...*
426467 """
427468 try :
428- if not self .dag :
429- raise ValueError (f"Unsolvable graph:\n { self } " )
430-
431- # Check plan<-->inputs mismatch.
432- #
433- missing = iset (self .needs ) - iset (named_inputs )
434- if missing :
435- raise ValueError (
436- f"Plan needs more inputs: { list (missing )} "
437- f"\n given inputs: { list (named_inputs )} \n { self } "
438- )
439-
440- if outputs is not None :
441- unknown = (
442- iset (astuple (outputs , "outputs" , allowed_types = abc .Sequence ))
443- - self .provides
444- )
445- if unknown :
446- raise ValueError (
447- f"Impossible outputs: { list (unknown )} \n for graph: { self } "
448- f"\n { self } "
449- )
469+ self .validate (named_inputs , outputs )
450470
451471 # choose a method of execution
452472 executor = (
@@ -457,14 +477,13 @@ def execute(self, named_inputs, outputs=None, *, overwrites=None, method=None):
457477
458478 # If certain outputs asked, put relevant-only inputs in solution,
459479 # otherwise, keep'em all.
480+ # Note: clone and keep orignal inputs in solution intact
460481 solution = (
461482 {k : v for k , v in named_inputs .items () if k in self .dag .nodes }
462483 if self .evict
463484 else named_inputs .copy ()
464485 )
465486 executed = set ()
466-
467- # clone and keep orignal inputs in solution intact
468487 executor (solution , overwrites , executed )
469488
470489 # Validate eviction was perfect
@@ -473,7 +492,7 @@ def execute(self, named_inputs, outputs=None, *, overwrites=None, method=None):
473492 or is_skip_evictions ()
474493 # It is a proper subset when not all outputs calculated.
475494 or set (solution ).issubset (self .provides )
476- ), f"Evictions left more data{ list (iset (solution ) - iset (self .provides ))} than { self } !"
495+ ), f"Evictions left more data{ list (iset (solution ) - set (self .provides ))} than { self } !"
477496
478497 return solution
479498 except Exception as ex :
0 commit comments