On Wed, 3 Aug 2016 01:12 am, Robin Becker wrote: > A reportlab user found he was doing the wrong thing by calling canvas.save > repeatedly, our documentation says you should not use Canvas objects after > the save method has been used. The user had mixed results :( > > It would be better to make the canvas object completely immutable all the > way down when save has been called, but I think that's quite hard as these > objects have quite a large and varied set of attributes, lists other > objects dictionaries etc etc.
If save() is the only problematic method, that's easy to fix: class X: def _bad_save(self): raise RuntimeError("I told you not to call save() more than once!") def save(self): # do the actual saving # then replace the method: self.save = self._bad_save Hmmm... clever as that is, it's probably not clever enough, as users can still call the unbound save method: X.save(instance) So back to the really old-fashioned way: class X: def __init__(self): self._saved = False def save(self): if self._saved: raise RuntimeError("*wack with clue stick*") else: # do the actual saving self._saved = True > I can think of some strategies for making the object unusable eg changing > it's class and getting rid of __dict__, but that disallows referencing > valid properties eg pagesize, fontName, etc etc. It shouldn't disallow anything. class X: # implementation of everything, properties, etc. # as they are expected to work before saving def save(self): # do the actual save self.__class__ = SavedX class SavedX(X): # Override just the bits that need neutering # including save def save(self): raise RuntimeError("stop that!") The tricky bit may be preventing writes to the instance __dict__. I don't think it is practical to allow the user to add arbitrary attributes to the instance up to the point they call save(), then prevent them from doing the same. You might be able to get it to work, but with difficulty. Better to fix save() so you can call it multiple times without breaking the instance. If you can't do that, the least-worst alternative would be to use __slots__ for both X and SavedX so that the user can't add new attributes at all. But really, the right way to do this is to fix the class so that save() can be called multiple times. In your editor, does selecting Save twice corrupt the file you're working on? > Is there a way to recursively turn everything immutable? First you have to come up with a way to turn everything immutable. (Good luck with that.) Then apply it recursively to the object and all its attributes. -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list