chameleon.exc exceptions can't be cloned, much less pickled
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Chamelon Core |
Fix Released
|
Undecided
|
Unassigned |
Bug Description
This is important for chameleon itself, which clones exceptions while formatting them. Here is an example traceback. Down below you'll find ipython session with demonstration appropriate for turning into (part of) an unit test, and a discussion on alternative fixes:
.../eggs/
430
431 def pt_render(self, source=False, extra_context={}):
--> 432 result = PageTemplate.
433 assert isinstance(result, unicode)
434 return result
.../eggs/
78 showtal = True
79 return super(PageTemplate, self).pt_render(c, source=source, sourceAnnotatio
---> 80 showtal=showtal)
81
82
.../eggs/
111 TALInterpreter(
112 context, output, tal=not source, showtal=showtal,
--> 113 strictinsert=0, sourceAnnotatio
114 return output.getvalue()
115
.../eggs/
125 context['repeat'] = RepeatDict(
126
--> 127 result = self.template.
128
129 self.stream.
.../eggs/
123
124 base_renderer = super(BaseTemplate, self).render
--> 125 return base_renderer(
126
127 def __call__(self, *args, **kwargs):
.../eggs/
115 if 'repeat' not in k: k['repeat'] = RepeatDict({})
116
--> 117 return super(PageTemplate, self).render(**k)
118
119 def include(self, stream, econtext, rcontext):
-------
Here is a specific demonstration of the bug:
In [1]: import chameleon.exc, copy, cPickle
In [2]: template_error = chameleon.
In [3]: copy.copy(
-------
TypeError Traceback (most recent call last)
/.../<ipython console> in <module>()
/.../lib/
93 raise Error("
94
---> 95 return _reconstruct(x, rv, 0)
96
97
/.../lib/
321 if deep:
322 args = deepcopy(args, memo)
--> 323 y = callable(*args)
324 memo[id(x)] = y
325 if listiter is not None:
TypeError: __init__() takes exactly 3 arguments (1 given)
In [4]: cPickle.
-------
TypeError Traceback (most recent call last)
/.../<ipython console> in <module>()
/.../lib/
75 except AttributeError:
76 if getattr(self, "__slots__", None):
---> 77 raise TypeError("a class that defines __slots__ without "
78 "defining __getstate__ cannot be pickled")
79 try:
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled
-------
At least for copying problem, the issue seems to be that the signature required by TemplateError.
* Make all __init__() parameters optional. This is the simplest one. The copy() infrastructure will simply call __setstate__() with the __dict__ of the original exception after an empty.
* Provide a .__copy__() method.
* Provide .__reduce_ex__() or .__reduce__() method with a result compatible with the existing .__init__() signature.
For the second problem, the fix might be harder, and maybe unnecessary, if we cannot find good use cases for pickling such an exception.
description: | updated |
Exceptions can now be cloned.
Whoever wants exceptions raised by Chameleon to be pickleable should reopen this issue