class Workflow(object):
    """Abstract base class defining a workflow, based on a flowpipe graph.

    The Workflow holds a graph and provides two ways to evaluate the graph,
    locally and remotely.
    """
    def __init__(self):
        self.graph = Graph()

    def evaluate_locally(self):
        """Evaluate the graph locally."""
        self.graph.evaluate()

    def evaluate_remotely(self):
        """See examples/vfx_render_farm_conversion.py on how to implement a
        conversion from flowpipe graphs to your render farm.
        """
        pass
# Connecting nodes can be done via the bit shift operator as well
build_walls.outputs["workers"]["0"] >> party.inputs["attendees"]["0"]
build_walls.outputs["workers"]["1"] >> party.inputs["attendees"]["2"]
build_roof.outputs["workers"]["0"] >> party.inputs["attendees"]["1"]
build_roof.outputs["workers"]["1"] >> party.inputs["attendees"]["3"]

# Initial values can be set onto the input plugs for initialization
party.inputs["attendees"]["4"].value = "Homeowner"

print("---------------------------------------")
print(graph.name)
print(graph)
print(graph.list_repr())
print("---------------------------------------")
graph.evaluate()
print("---------------------------------------")

graph = Graph(name="Celebrate a Birthday Party")


@Node(outputs=["people"])
def InvitePeople(amount):
    people = ["John", "Jane", "Mike", "Michelle"]
    d = {"people.{0}".format(i): people[i] for i in range(amount)}
    d["people"] = {people[i]: people[i] for i in range(amount)}
    return d


invite = InvitePeople(graph=graph, amount=4)
birthday_party = Party(graph=graph, name="Birthday Party")