2016-03-01 11 views
5

Wie kann ich einfach ein Objekt erstellen, das nicht zum Testen von Randfällen in meinem RPC-Code verwendet werden kann?Objekt erstellen, das nicht gebeizt werden kann

Es muss sein:

  1. Einfache
  2. Zuverlässige
  3. Plattformübergreifend

Edit (nicht in zukünftigen Versionen von Python oder Beize zu brechen erwartet): Aussehen Die bestimmungsgemäße Verwendung etwas wie dieses:

class TestRPCServer: 
    def foo(self): 
     return MagicalUnpicklableObject() 

def test(): 
    with run_rpc_server_and_connect_to_it() as proxy: 
     with nose.assert_raises(pickle.PickleError): 
      proxy.foo() 
+0

Was baust du? Können wir einen Beispielcode für das fragliche Objekt haben? – GLaDOS

Antwort

6

Wenn alles, was Sie brauchen, ein Objekt ist, das eine Ausnahme auslöst, wenn Sie es einbeißen, können Sie für den Test das __getstate__ method sprengen.

>>> class C: 
...  def __getstate__(self): 
...   raise Exception 
... 
>>> pickle.dumps(C()) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1374, in dumps 
    Pickler(file, protocol).dump(obj) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 723, in save_inst 
    stuff = getstate() 
    File "<stdin>", line 3, in __getstate__ 
Exception 

Kaum einfacher als das!


Wenn Sie ein weniger künstliches Szenario wollen, denken Sie Objekte, die OS-Ressourcen wie Datei-Handles verwenden oder Sockets oder Fäden usw.

>>> with open('spam.txt', 'w') as f: 
...  pickle.dumps(f) 
... 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1374, in dumps 
    Pickler(file, protocol).dump(obj) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 306, in save 
    rv = reduce(self.proto) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy_reg.py", line 70, in _reduce_ex 
    raise TypeError, "can't pickle %s objects" % base.__name__ 
TypeError: can't pickle file objects 
+0

Der erste Weg scheint genau das zu sein, was ich brauche, danke. Ich bin stecken geblieben, weil ich versucht habe, PickleError zu werfen, was eigentlich unnötig ist. Eine benutzerdefinierte Ausnahmeklasse zu erstellen und zu werfen ist genug. – cube

2

Wenn Sie eine explizite Liste von Objekten mag, dass können gegen Objekte gebeizt werden, die nicht gebeizt werden können, sowohl mit pickle als auch mit fortgeschritteneren Serialisierern wie dill, diese Datei enthält eine etwas umfassende Liste für Standardbibliotheksobjekte. Es bietet eine einfache Möglichkeit, jedes Objekt (normalerweise ein Einzeiler) zu erstellen, und zeigt gegebenenfalls Varianten für verschiedene Versionen von Python an.

https://github.com/uqfoundation/dill/blob/cccbea9b715e16b742288e1e5a21a687a4d4081b/dill/_objects.py#L255

Zum Beispiel pickle die folgende Aufgabe scheitern, während erweiterte Serializer wie dill werden nicht:

>>> import dill 
>>> dill.dumps(Ellipsis) 
b'\x80\x03cdill.dill\n_eval_repr\nq\x00X\x08\x00\x00\x00Ellipsisq\x01\x85q\x02Rq\x03.' 

Erweiterte Serializer auch auf Dateiobjekte und dergleichen arbeiten können, btw:

>>> dill.dumps(open('foo.pkl', 'w')) 
b'\x80\x03cdill.dill\n_create_filehandle\nq\x00(X\x07\x00\x00\x00foo.pklq\x01X\x01\x00\x00\x00wq\x02K\x00\x89cdill.dill\n_get_attr\nq\x03cdill.dill\n_import_module\nq\x04X\x02\x00\x00\x00ioq\x05\x85q\x06Rq\x07X\x04\x00\x00\x00openq\x08\x86q\tRq\n\x89K\x00X\x00\x00\x00\x00q\x0btq\x0cRq\r.' 

jedoch pickle und dill (Und andere fortgeschrittene Serializer) wird auf jede Art fehlschlagen, die direkt an eine Python gebunden ist FrameType, wie ein Generator:

>>> dill.dumps((i for i in [])) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/Users/mmckerns/lib/python3.4/site-packages/dill-0.2.6.dev0-py3.4.egg/dill/dill.py", line 243, in dumps 
    dump(obj, file, protocol, byref, fmode, recurse)#, strictio) 
    File "/Users/mmckerns/lib/python3.4/site-packages/dill-0.2.6.dev0-py3.4.egg/dill/dill.py", line 236, in dump 
    pik.dump(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/pickle.py", line 412, in dump 
    self.save(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/pickle.py", line 499, in save 
    rv = reduce(self.proto) 
TypeError: can't pickle generator objects 
Verwandte Themen