Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for generating state diagram without writing the file to disk #533

Closed
Blindfreddy opened this issue May 18, 2021 · 6 comments
Closed
Assignees

Comments

@Blindfreddy
Copy link

Blindfreddy commented May 18, 2021

Is your feature request related to a problem? Please describe.
My program has a REST API and returns data in JSON. I'd like to also return the state diagram rendered using transitions get_graph().draw(). Currently, the get_graph().draw() method firstly writes the rendered state diagram to local filesystem, from where I read it, base64 encode it and return it in response to a GET request.

Describe the solution you'd like
Render the diagram but don't write it to disk, instead return the stream, or better still directly base64 encode it, thus eliminating the two-step procedure of first writing a file and then reading that file for encoding and returning in the API.

Additional context
Add any other context or screenshots about the feature request here.

Current implementation is as follows; it works but note the two steps: first create the file , then read it and base64 encode it. It would be great if the file were not written to the filesystem but directly returned by the draw() method.

    @property
    def state_diagram(self):
        filename = uuid.uuid4().hex
        self._sm.get_graph(show_roi=True).draw(filename, prog='dot')
        with open(filename, mode='rb') as f:
            content = f.read()
        d = {'name' : self.name,
             'filename' : self.name + '_state_diagram.png',
             'mimetype' : 'image/png',
             'encoding' : 'base64',
             'value' : b64encode(content).decode()}
        os.remove(filename)
        return d         
@aleneum
Copy link
Member

aleneum commented Jun 28, 2021

Hello @Blindfreddy,

I kept you waiting waaaaay too long. The problem is that GraphMachine.get_graph returns a pygraphviz.Agraph object when you use pygraphviz (default backend) and a transitions.Graph when you use graphviz. transitions has no influence on Agraph.draw but from the documentation it seems like just setting path to None does what you require:

Note, if path is a file object returned by a call to os.fdopen(), then the method for discovering the format will not work.
In such cases, one should explicitly set the format parameter; otherwise, it will default to 'dot'.
If path is None, the result is returned as a Bytes object.

from transitions.extensions import GraphMachine

m = GraphMachine(states=['A', 'B'], transitions=[['go', 'A', 'B']], initial='A')
g = m.get_graph().draw(None, prog='dot', format='jpeg')
print(g)
# >>> b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01 ...

I will have a look to implement a similar behaviour for the graphviz backend.

@Blindfreddy
Copy link
Author

Hi @aleneum
Thanks for the response, sounds like a plan. In the meantime I implemented a workaround which writes the file locally, reads it and then deletes it. Not pretty but works.

        filename = uuid4().hex + '.png'
        self._sm.get_graph(show_roi=True).draw(filename, prog='dot')
        with open(filename, mode='rb') as f:
            content = f.read()
            ...
        os.remove(filename)

@aleneum
Copy link
Member

aleneum commented Jul 15, 2021

Hi,

in 9370834, I implemented the aforementioned behaviour. Let me know if this works for you. If you are happy with your workaround, you can also go ahead and just close this issue.

@Blindfreddy
Copy link
Author

I'm afraid I don't know how to install the abovementioned commit using pip prior to release 0.8.9. Tried
git+git://github.com/pytransitions/transitions/commit/9370834b412d7d0efecae520bf672b4931fb1a38 to no avail, any help with getting it installed would be much appreciated. Otherwise wait until 0.8.9 is released.

@aleneum
Copy link
Member

aleneum commented Aug 3, 2021

you could just install transitions from master I guess:

pip install git+https://github.com/pytransitions/transitions

@aleneum
Copy link
Member

aleneum commented Sep 2, 2021

0.8.9 has been released which includes the requested feature. I will close this issue. Feel free to comment if you consider this issue not resolved. I will reopen the issue if required.

@aleneum aleneum closed this as completed Sep 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants