classification
Title: __setstate__ is called for false values
Type: Stage:
Components: Library (Lib) Versions: Python 3.3, Python 3.2, Python 3.1, Python 2.7, Python 2.6
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: alexandre.vassalotti, belopolsky, eltoder, georg.brandl, pitrou, r.david.murray
Priority: normal Keywords: patch

Created on 2011-06-09 02:20 by eltoder, last changed 2011-06-18 08:26 by georg.brandl.

Files
File name Uploaded Description Edit
setstate.diff eltoder, 2011-06-16 02:57
Messages (4)
msg137935 - (view) Author: Eugene Toder (eltoder) Date: 2011-06-09 02:20
Pickle documentation [1] says:

""" Note: If __getstate__() returns a false value, the __setstate__() method will not be called upon unpickling. """

However, this isn't quite true. This depends on the version of pickle protocol. A small example:

>>> class Pockle(object):
	def __getstate__(self):
		return 0
	def __setstate__(self, state):
		sys.stdout.write('__setstate__ is called!\n')

>>> for p in range(4):
	sys.stdout.write('protocol %d: ' % p)
	pickle.loads(pickle.dumps(Pockle(), p))

protocol 0: <__main__.Pockle object at 0x0000000002EAE3C8>
protocol 1: <__main__.Pockle object at 0x0000000002EAE358>
protocol 2: __setstate__ is called!
<__main__.Pockle object at 0x0000000002EAE3C8>
protocol 3: __setstate__ is called!
<__main__.Pockle object at 0x0000000002EAE358>

So for protocols >= 2 setstate is called. This is caused by object.__reduce_ex__ returning different tuples for different protocol versions:

>>> for p in range(4):
	sys.stdout.write('protocol %d: %s\n' % (p, Pockle().__reduce_ex__(p)))

	
protocol 0: (<function _reconstructor at 0x0000000001F03048>, (<class '__main__.Pockle'>, <class 'object'>, None))
protocol 1: (<function _reconstructor at 0x0000000001F03048>, (<class '__main__.Pockle'>, <class 'object'>, None))
protocol 2: (<function __newobj__ at 0x0000000001F03148>, (<class '__main__.Pockle'>,), 0, None, None)
protocol 3: (<function __newobj__ at 0x0000000001F03148>, (<class '__main__.Pockle'>,), 0, None, None)

Implementation of reduce_ex for protos 0-1 in copy_reg.py contains the documented check: http://hg.python.org/cpython/file/f1509fc75435/Lib/copy_reg.py#l85

Implementation for proto 2+ in typeobject.c is happy with any value: http://hg.python.org/cpython/file/f1509fc75435/Objects/typeobject.c#l3205

Pickle itself only ignores None, not any false value: http://hg.python.org/cpython/file/f1509fc75435/Lib/pickle.py#l418

I think this is a documentation issue at this point.

[1] http://docs.python.org/py3k/library/pickle.html#pickle.object.__setstate__
msg137936 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2011-06-09 02:37
See also #6827, just for some background on the current docs.
msg138410 - (view) Author: Eugene Toder (eltoder) Date: 2011-06-16 02:57
So how about this correction?
msg138573 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2011-06-18 08:26
Well, this looks correct then.
History
Date User Action Args
2011-06-18 08:26:22georg.brandlsetmessages: + msg138573
2011-06-16 02:57:48eltodersetfiles: + setstate.diff

nosy: + georg.brandl, belopolsky
messages: + msg138410

keywords: + patch
2011-06-09 02:59:01eltodersetnosy: + pitrou, alexandre.vassalotti
2011-06-09 02:37:22r.david.murraysetnosy: + r.david.murray
messages: + msg137936
2011-06-09 02:20:57eltodercreate