2011-12-05 9 views
6

C'è un modo per far sì che Python pickle ignori gli errori "non è lo stesso oggetto"?C'è un modo per fare in modo che Python pickle ignori errori "non è lo stesso oggetto"

Sto scrivendo un test utilizzando Mock per avere un controllo a grana fine sui risultati prodotti da datetime.utcnow(). Il codice che sto usando è time sensitive, quindi la patch di mock rende facile testare.

Gli stessi test devono decodificare gli oggetti e inviare i risultati a un server remoto. Ai fini del test se un datetime standard è stato decapitato e ricevuto dal server remoto, tutto andrebbe bene.

Purtroppo il modulo pickle è barfing con il seguente errore:

Can't pickle <type 'datetime.datetime'>: it's not the same object as datetime.datetime

Ecco un esempio minimo per riprodurre l'errore.

from mock import patch 
from datetime import datetime 
import pickle 

class MockDatetime(datetime): 
    frozendt = datetime(2011,05,31) 

    @classmethod 
    def advance(cls, **kw): 
    cls.frozendt = cls.frozendt + timedelta(**kw) 

    @classmethod 
    def utcnow(cls): 
    return cls.frozendt 

@patch('datetime.datetime', MockDatetime) 
def test(): 
    pickle.dumps(datetime.utcnow()) 

if __name__ == '__main__': 
    test() 

C'è qualche combo di __reduce__ e __getstate__ metodi che potrebbero ingannare i macchinari salamoia a pensare MockDatetime è un datetime quando Pickle?

risposta

5

Guardando la sezione where to patch nella documentazione vedo questo consiglio:

The basic principle is that you patch where an object is used, which is not necessarily the same place as where it is defined.

A seguito di questa raccomandazione, ho provato a sostituire:

@patch('datetime.datetime', MockDatetime) 

con:

@patch('__main__.datetime', MockDatetime) 

e non ho ricevuto alcun errore da pickle. Inoltre, ho aggiunto una dichiarazione print per assicurarmi che lo datetime venisse effettivamente applicato e ho ottenuto il valore previsto.

2

Nel caso in cui qualcuno vuole una soluzione generica per salamoia prende in giro:

m = mock.MagicMock() 
m.__reduce__ = lambda self: (mock.MagicMock,()) 

Si noti che questo non sembra per salvare il contenuto interno del finto utilizzato (per esempio le chiamate).