def needed_inputs(self):
        """ List all the needed inputs of a configured engine

        >>> engine = Engine("op1", "op2")
        >>> engine.op1.setup(in_name="in", out_name="middle", required=False)
        >>> engine.op2.setup(in_name="middle", out_name="out")
        >>> engine.op1.append(lambda x:x+2)
        >>> engine.op2.append(lambda x:x*2)
        >>> engine.op1.select('<lambda>')
        >>> list(engine.needed_inputs())
        ['in']

        But now if we unactivate the first component:

        >>> engine.op1.clear_selections()
        >>> list(engine.needed_inputs())
        ['middle']

        More complex example:

        >>> engine = Engine("op1", "op2")
        >>> engine.op1.setup(in_name="in", out_name="middle")
        >>> engine.op2.setup(in_name=["middle", "in2"], out_name="out")
        >>> engine.op1.append(lambda x:x+2)
        >>> engine.op2.append(lambda x, y:x*y)
        >>> engine.needed_inputs() == {'in', 'in2'}
        True

        Note that by default the needed input is 'input':
        
        >>> engine = Engine("op1", "op2")
        >>> engine.op1.append(lambda x:x+2)
        >>> engine.op2.append(lambda x:x*2)
        >>> list(engine.needed_inputs())
        ['input']
        """
        needed = set()
        available = set()       # set of available data
        for bnum, block in enumerate(self):
            if not block.selected():    # if the block will not be used
                continue
            if block.in_name is not None:
                for in_name in block.in_name:
                    if not in_name in available:
                        needed.add(in_name)
            elif bnum == 0:
                # if the first block
                needed.add(Engine.DEFAULT_IN_NAME)
            # register the output
            available.add(block.out_name)
        return needed
List all the needed inputs of a configured engine

        >>> engine = Engine("op1", "op2")
        >>> engine.op1.setup(in_name="in", out_name="middle", required=False)
        >>> engine.op2.setup(in_name="middle", out_name="out")
        >>> engine.op1.append(lambda x:x+2)
        >>> engine.op2.append(lambda x:x*2)
        >>> engine.op1.select('<lambda>')
        >>> list(engine.needed_inputs())
        ['in']

        But now if we unactivate the first component:

        >>> engine.op1.clear_selections()
        >>> list(engine.needed_inputs())
        ['middle']

        More complex example:

        >>> engine = Engine("op1", "op2")
        >>> engine.op1.setup(in_name="in", out_name="middle")
        >>> engine.op2.setup(in_name=["middle", "in2"], out_name="out")
        >>> engine.op1.append(lambda x:x+2)
        >>> engine.op2.append(lambda x, y:x*y)
        >>> engine.needed_inputs() == {'in', 'in2'}
        True

        Note that by default the needed input is 'input':
        
        >>> engine = Engine("op1", "op2")
        >>> engine.op1.append(lambda x:x+2)
        >>> engine.op2.append(lambda x:x*2)
        >>> list(engine.needed_inputs())
        ['input']