I've updated cPickle.c to use class exceptions:
Changed pickle error types to classes:
PickleError
PicklingError
UnpickleableError
UnpicklingError
And change the handling of unpickleable objects so that an UnpickleableError
is raised with the unpickleable object as the argument. UnpickleableError
has a reasonable string representation and provides access to the problem
object, which is useful during debugging.
[I'm still waiting for patches to do the same to pickle.py.]
I have attached a new cPickle that adds a new control attribute
to unpicklers:
Added new Unpickler attribute, find_global. If set to None, then
global and instance pickles are disabled. Otherwise, it should be set to
a callable object that takes two arguments, a module name and an
object name, and returns an object. If the attribute is unset, then
the default mechanism is used.
This feature provides an additional mechanism for controlling which
classes can be used for unpickling.
- New copyright. (Open source)
- Added new protocol for binary string pickles that
takes out unneeded puts:
p=Pickler()
p.dump(x)
p.dump(y)
thePickle=p.getvalue()
This has little or no impact on pickling time, but
often reduces unpickling time and pickle size, sometimes
significantly.
- Changed unpickler to use internal data structure instead
of list to reduce unpickling times by about a third.
- Many cleanups to get rid of obfuscated error handling
involving 'goto finally' and status variables.
- Extensive reGuidofication. (formatting :)
- Fixed binary floating-point pickling bug. 0.0 was not
pickled correctly.
- Now use binary floating point format when saving
floats in binary mode.
- Fixed some error message spelling error.
I had to make a slight diddle to work with Python 1.4, which
we and some of our customers are still using. :(
I've also made a few minor enhancements:
- You can now both get and set the memo using a 'memo'
attribute. This is handy for certain advanced applications
that we have.
- Added a 'binary' attribute to get and set the binary
mode for a pickler.
- Added a somewhat experimental 'fast' attribute. When this
is set, objects are not placed in the memo during pickling.
This should lead to faster pickling and smaller pickles in
cases where:
o you *know* there are no circular references, and
o either you've:
- preloaded the memo with class information
by pickling classes in non-fast mode or by
manipilating the memo directly, or
- aren't pickling instances.
1. Only DECREF the class's module when the module is retrieved via
PyImport_Import. If it is retrieved from the modules dictionary with
PyDict_GetItem, it is using a borrowed reference.
2. If the module doesn't define the desired class, raise the same
SystemError that pickle.py does instead of returning an AttributeError
(which is cryptic at best).
Also, fix the PyArg_ParseTuple in cpm_loads (the externally visible
loads) function: Use "S" instead of "O" because cStringIO will croak
with a "bad arguments to internal function" if passed anything other
than a string.
- Loading non-binary string pickles checks for insecure
strings. This is needed because cPickle (still)
uses a restricted eval to parse non-binary string pickles.
This change is needed to prevent untrusted
pickles like::
"S'hello world'*2000000\012p0\012."
from hosing an application.
- User-defined types can now support unpickling without
executing a constructor.
The second value returned from __reduce__ can now be None,
rather than an argument tuple. On unpickling, if the second
value returned from __reduce__ during pickling was None, then
rather than calling the first value returned from __reduce__,
directly, the __basicnew__ method of the first value returned
from __reduce__ is called without arguments.
- Quieted gcc -Wall by removing unused local variables.
- Added some choice parentheses around assignments in conditional
tests.
- Removed an unused (and seemingly unreachable) err label in
load_short_binstring().
- in Unpickler_load(), removed \. in string format.
- init_stuff() was declared to return an int, but had these
problems:
- it was returning NULL instead of 0 or 1 in some cases
- it was falling of the end of the routine without returning
anything
- the call of init_stuff() in initcPickle() was never checking
the return value anyway.
I changed all this by returning 1 in the case of errors, 0 when
no error occurred. Then in initcPickle(), if init_stuff()
returns non-zero, I call Py_FatalError().
Suppressing my urge to reformat according to Python coding standards!
:-)