What API design would you like to have changed or added to the library? Why?
Currently, if a AutoPipelineBlocks contains 2 branch blocks; if both have the same input, one branch block declares a default while the other does not; both blocks will have the same default, so that the default value set in one branch will leak into the sibling one, which is unexpected
What use case would this enable or better enable? Can you give us a code example?
"""Repro: in an AutoPipelineBlocks, a default declared by one branch leaks into thesibling branch via `combine_inputs` (non-None default overwrites None) + globaldefault-filling of PipelineState in `ModularPipeline.__call__`.The sibling branch uses `None` as a "user didn't pass this" sentinel, so it canreject explicitly-passed values. The leaked default makes that check fire onevery run even when the user never passed the input."""fromdiffusers.modular_pipelinesimportAutoPipelineBlocks, ModularPipelineBlocksfromdiffusers.modular_pipelines.modular_pipeline_utilsimportInputParam, OutputParamclassPlainStep(ModularPipelineBlocks):
model_name="dummy"@propertydefdescription(self):
return"Plain branch: declares a real default for num_frames."@propertydefinputs(self):
return [InputParam(name="num_frames", default=189)]
@propertydefintermediate_outputs(self):
return [OutputParam("resolved_num_frames")]
def__call__(self, components, state):
block_state=self.get_block_state(state)
block_state.resolved_num_frames=block_state.num_framesself.set_block_state(state, block_state)
returncomponents, stateclassActionStep(ModularPipelineBlocks):
model_name="dummy"@propertydefdescription(self):
return"Action branch: num_frames must NOT be passed (derived from action)."@propertydefinputs(self):
return [
InputParam(name="action", required=True),
InputParam(name="num_frames", default=None),
]
@propertydefintermediate_outputs(self):
return [OutputParam("resolved_num_frames")]
def__call__(self, components, state):
block_state=self.get_block_state(state)
ifblock_state.num_framesisnotNone:
raiseValueError("`num_frames` has to be None if `action` is provided.")
block_state.resolved_num_frames=100# pretend: derived from actionself.set_block_state(state, block_state)
returncomponents, stateclassAutoStep(AutoPipelineBlocks):
model_name="dummy"block_classes= [ActionStep, PlainStep]
block_names= ["action", "plain"]
block_trigger_inputs= ["action", None]
@propertydefdescription(self):
return"Runs ActionStep when `action` is provided, PlainStep otherwise."auto=AutoStep()
merged= {p.name: p.defaultforpinauto.inputs}
print(f"merged pipeline-level inputs: {merged}")
print(f" -> ActionStep declared num_frames default=None, but merged default is {merged['num_frames']}\n")
pipe=auto.init_pipeline()
print("1) plain path, no num_frames passed:")
state=pipe()
print(f" resolved_num_frames = {state.get('resolved_num_frames')} (default worked)\n")
print("2) action path, user does NOT pass num_frames:")
try:
pipe(action="dummy-action")
exceptValueErrorase:
print(f" ValueError: {e}")
print(" ^ spurious! the user never passed num_frames — PlainStep's default=189")
print(" was filled into state before branch selection, so ActionStep cannot")
print(" tell 'user passed 189' from 'default filled 189'.")you can get away from the unexpected behavior by not setting a default in InputParam, and handle the default value assignment inside call of each branch
like in #14110, but I think we should fix this on our end
What API design would you like to have changed or added to the library? Why?
Currently, if a
AutoPipelineBlockscontains 2 branch blocks; if both have the same input, one branch block declares a default while the other does not; both blocks will have the same default, so that the default value set in one branch will leak into the sibling one, which is unexpectedWhat use case would this enable or better enable? Can you give us a code example?
you can get away from the unexpected behavior by not setting a default in InputParam, and handle the default value assignment inside call of each branch
like in #14110, but I think we should fix this on our end