pydot icon indicating copy to clipboard operation
pydot copied to clipboard

Complex edges break pickling (due to unpicklable FrozenDict)

Open ferdnyc opened this issue 8 months ago • 5 comments

Let me preface this by saying that I could not possibly care less about this issue — I'm always amazed that anyone still uses pickle at all, anymore. Using it to serialize Pydot data seems especially silly, because it makes far more sense to just serialize as a dot file and re-parse it on load, if someone really needs to store their graphs.

But, it's something I discovered in experimenting, so I wanted to at least document it. I don't have any plans to fix it, heck I'm not even sure if it is fixable.

Because complex edges are partly made up of FrozenDict objects, graphs that include them are no longer picklable. Writing out the data will work fine, but when attempting to load it back in Python will throw out a Traceback originating in:

AttributeError: A frozendict cannot be modified.

(Including the incorrect casing; I forgot to update the message when I renamed the class to FrozenDict.)

AFAICT it's always been this way... I loaded up Pydot v1.4.2 and attempted to pickle a frozendict from that version of the code, and got the same exact traceback.

The only difference is, now that we support complex edges, there will be FrozenDicts in the graph data. There never were, before, because they're only used for subgraphs on edge endpoints.

This issue only affects graphs that use complex edges, for the same reason. So, as far as I care, that's fine: Complex edges are incompatible with pickle, so users can choose one or the other (or neither). ¯\_(ツ)_/¯

ferdnyc avatar May 16 '25 03:05 ferdnyc

I foresee a possibility of user-friendly pickling errors when a complex edge is detected in the graph, implemented in the __getstate__ method. That's probably a feature that nobody will ever use.

lkk7 avatar May 16 '25 10:05 lkk7

PRs welcome! 😁

ferdnyc avatar May 16 '25 10:05 ferdnyc

BTW, from what I remember, Pydot pickling isn't really stable and supported anyway - lots of issues with that keyword and an old PR that tries to fix it https://github.com/pydot/pydot/pull/242

lkk7 avatar Oct 26 '25 19:10 lkk7

@lkk7

AFAIK, pickling is now fully supported and working properly except when FrozenDicts are involved. The issue that #242 was aiming to correct was that, at the time, the convenience methods were being created during instance __init__, but unpickled objects DON'T get __init__()-ed. (They get __new__()-ed, followed by a call to __setstate__().)

But we moved the convenience-method creation to the class level, and I discovered the issues with unpickling Dot objects while writing tests, documented it in #402, and fixed it with #403.

At that point, AFAIK pickling was completely supported, working, and tested... uuuuuntil I introduced FrozenDicts into the obj_dict['edges'] keys, which broke it again.

ferdnyc avatar Oct 29 '25 19:10 ferdnyc

(#242 can definitely be closed, everything it was looking to solve has already been addressed in other ways.)

ferdnyc avatar Oct 29 '25 19:10 ferdnyc