Consider the following class, which inherits from datetime.time
:
class TimeWithAddSub(time):
_date_base = date(2000, 1, 1)
def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
obj = super(TimeWithAddSub, cls).__new__(cls, hour, minute, second, microsecond, tzinfo)
obj._as_datetime = datetime(2000, 1, 1, hour, minute, second, microsecond, tzinfo=tzinfo)
return obj
Trying to unpickle it gives the following error:
>>> t = TimeWithAddSub(10, 11, 12)
>>> b = pickle.dumps(t)
>>> b'\x80\x04\x95T\x00\x00\x00\x00\x....'
>>> t2 = pickle.loads(b)
>>> ... in __new__ ... TypeError: 'bytes' object cannot be interpreted as an integer
After some digging, it seems that the __new__()
function in the unpickled object does not get the correct parameters:
hour
is set to b'\x0b\x0c\r\x00\x00\x00'
minute=0, second=0, microsecond=0, tzinfo=None
)I've tried overriding __reduce__()
and then __getnewargs__()
, but both approaches result in the same error.
Any ideas how to fix this?
The problem was that datetime.time
implements __reduce_ex__()
, which takes precedence over __reduce__()
.
Once I implemented TimeWithAddSub.__reduce_ex__()
, overriding the implementation in the base class, the problem was resolved:
class TimeWithAddSub(time):
_date_base = date(2000, 1, 1)
def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
obj = super(TimeWithAddSub, cls).__new__(cls, hour, minute, second, microsecond, tzinfo)
obj._as_datetime = datetime(2000, 1, 1, hour, minute, second, microsecond, tzinfo=tzinfo)
return obj
def __reduce_ex__(self, protocol):
return type(self), (self.hour, self.minute, self.second, self.microsecond, self.tzinfo)