0

I tried creating a Diagram using the NarcolepticSuperhero machine defined in the GitHub documentation but it only outputs this:

enter image description here

Steps to recreate:

  1. Create a file named test.py, with this content:
    from transitions import Machine
    from transitions.extensions import GraphMachine
    import random
    
    class NarcolepticSuperhero(object):
    
        # Define some states. Most of the time, narcoleptic superheroes are just like
        # everyone else. Except for...
        states = ['asleep', 'hanging out', 'hungry', 'sweaty', 'saving the world']
    
        def __init__(self, name):
    
            # No anonymous superheroes on my watch! Every narcoleptic superhero gets
            # a name. Any name at all. SleepyMan. SlumberGirl. You get the idea.
            self.name = name
    
            # What have we accomplished today?
            self.kittens_rescued = 0
    
            # Initialize the state machine
            self.machine = Machine(model=self, states=NarcolepticSuperhero.states, initial='asleep')
    
            # Add some transitions. We could also define these using a static list of
            # dictionaries, as we did with states above, and then pass the list to
            # the Machine initializer as the transitions= argument.
    
            # At some point, every superhero must rise and shine.
            self.machine.add_transition(trigger='wake_up', source='asleep', dest='hanging out')
    
            # Superheroes need to keep in shape.
            self.machine.add_transition('work_out', 'hanging out', 'hungry')
    
            # Those calories won't replenish themselves!
            self.machine.add_transition('eat', 'hungry', 'hanging out')
    
            # Superheroes are always on call. ALWAYS. But they're not always
            # dressed in work-appropriate clothing.
            self.machine.add_transition('distress_call', '*', 'saving the world',
                                before='change_into_super_secret_costume')
    
            # When they get off work, they're all sweaty and disgusting. But before
            # they do anything else, they have to meticulously log their latest
            # escapades. Because the legal department says so.
            self.machine.add_transition('complete_mission', 'saving the world', 'sweaty',
                                after='update_journal')
    
            # Sweat is a disorder that can be remedied with water.
            # Unless you've had a particularly long day, in which case... bed time!
            self.machine.add_transition('clean_up', 'sweaty', 'asleep', conditions=['is_exhausted'])
            self.machine.add_transition('clean_up', 'sweaty', 'hanging out')
    
            # Our NarcolepticSuperhero can fall asleep at pretty much any time.
            self.machine.add_transition('nap', '*', 'asleep')
    
        def update_journal(self):
            """ Dear Diary, today I saved Mr. Whiskers. Again. """
            self.kittens_rescued += 1
    
        @property
        def is_exhausted(self):
            """ Basically a coin toss. """
            return random.random() < 0.5
    
        def change_into_super_secret_costume(self):
            print("Beauty, eh?")
            
    batman = NarcolepticSuperhero("Batman")
    batman.wake_up()
    batman.state
    
    machine = GraphMachine(model=batman)
    batman.get_graph().draw("test.png", prog='dot')
  1. Install the requirements (Ubuntu 20.10, I tested on it's docker image) and run the script:
$ apt install graphviz graphviz-dev
$ pip3 install transitions graphviz pygraphviz
$ python3 test.py
  1. Check the generated image
aleneum
  • 2,083
  • 12
  • 29
kauedg
  • 827
  • 8
  • 20

1 Answers1

2

You are instantiating a GraphMachine without any states and transitions here:

machine = GraphMachine(model=batman)

You basically reuse NarcolepticSuperhero as a model for that new machine but what you should do instead is changing the NarcolepticSuperhero's machine into a GraphMachine:

            # Initialize the state machine
            self.machine = GraphMachine(model=self, states=NarcolepticSuperhero.states, initial='asleep')

# [...]
    batman.state
    
    # this is not required anymore
    # machine = GraphMachine(model=batman)
    batman.get_graph().draw("test.png", prog='dot')
aleneum
  • 2,083
  • 12
  • 29
  • Let's say I can't change the NarcolepticSuperhero class. Would it be possible to replace the already initialized batman.machine instance's class type from Machine to GraphMachine? – kauedg Sep 02 '21 at 01:13
  • 1
    @kauedg: It is possible but since models are decorated with convenience functions tied to a machine instance, replacing a machine with another one requires some adjustments. You'd probably need to override `Machine._checked_assignment`. For more details, check this [GitHub Issue](https://github.com/pytransitions/transitions/issues/436). – aleneum Sep 02 '21 at 11:21
  • Thank you for this. The documentation isn't clear on how GraphMachine replaces Machine in this scenario – Thomas R Jul 07 '22 at 21:22