-
Notifications
You must be signed in to change notification settings - Fork 475
WIP: Fix deepcopy-ing of CFFs #1488
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
Conversation
I was checking as well during my flight, but I don’t think it’s that. It has to do with the custom |
Yeah, implementing def __deepcopy__(self, memo):
from copy import deepcopy
cls = self.__class__
obj = cls.__new__(cls)
for k, v in self.__dict__.items():
if k == "otFont":
obj.otFont = None
else:
obj.__dict__[k] = deepcopy(v, memo)
return obj on CFFFontSet doesn't help. I suppose that it is still problematic to store a reference to the parent TTFont object we want to deepcopy? |
Stepping through this, it seems that |
Actually, there's infinite recursion even when I remove the |
Maybe because |
I have no internet on my laptop so I just sent you a photo of a git patch via WhatsApp LOL 😂 |
😁
|
We need to implement custom |
We need to raise AttributeError for non-existing dunder methods like '__deepcopy__' or '__getstate__', because deepcopy() and pickle.load() test for these on the instance using getattr() and treat the resulting AttributeError as a signal that the object doesn't implement these custom hooks. If we don't do that, we enter an infinite recursion as we attempt to look up the missing dunder methods in the 'rawDict' dictionary, because 'rawDict' is set inside __init__, but __init__ is not invoked while unpickling (only __new__ is); thus self.rawDict is also missing and __getattr__ is invoked with argument 'rawDict' again and again until it crashes with RecursionError. Phew. Fixes #1488
fixed on master with 649dc49 |
We need to raise AttributeError for non-existing dunder methods like '__deepcopy__' or '__getstate__', because deepcopy() and pickle.load() test for these on the instance using getattr() and treat the resulting AttributeError as a signal that the object doesn't implement these custom hooks. If we don't do that, we enter an infinite recursion as we attempt to look up the missing dunder methods in the 'rawDict' dictionary, because 'rawDict' is set inside __init__, but __init__ is not invoked while unpickling (only __new__ is); thus self.rawDict is also missing and __getattr__ is invoked with argument 'rawDict' again and again until it crashes with RecursionError. Phew. Fixes fonttools#1488
The dunder method doesn't seem to be doing anything other than providing an `in_cff2` attribute. Do that with a property instead of bending __getattr__. This one confused me when I was working on fonttools#1488.
Deepcopying a TTFont with a CFF table can result in an infinite recursion on Python 3 under certain circumstances.
@anthrotype found that CFFFontSet keeps a reference to the TTFont object that holds it to get at the glyph order at some point: https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/cffLib/__init__.py#L34. Maybe this messes with
deepcopy
.