2016-03-01 44 views
5

如何輕鬆創建一個不能被醃製的對象來測試我的rpc代碼中的邊緣案例?創建不能被醃製的對象

它需要:

  1. 簡單
  2. 可靠的(沒有預想中Python或泡菜的未來版本打破)
  3. 跨平臺

編輯:用途外觀像這樣:

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

你在構建?我們可以有問題的對象的示例代碼? – GLaDOS

回答

6

如果你所需要的只是一個物體,當你醃它時會拋出異常,對於測試的目的,你可以炸掉__getstate__ method

>>> 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 

幾乎沒有那麼簡單!


如果你想有一個人工少的情況下,想使用OS資源,如文件句柄,或者套接字或線程對象等

>>> 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

第一種方式似乎正是我所需要的,謝謝。我被卡住了,因爲我試圖讓它拋出PickleError,這實際上是不必要的。製作一個自定義的異常類並投擲就足夠了。 – cube

2

如果你想對象的明確列表可以使用pickle以及更高級的序列化器(如dill)對不能被酸洗的對象進行酸洗,該文件包含標準庫對象的一個​​比較全面的列表。它提供了一種簡單的方法來構建每個對象(通常是一行代碼),並顯示不同版本的Python的變體(如果適用)。

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

例如,pickle將下列對象上失敗了,而像dill先進的串行器將不會:

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

高級串行還可以在文件對象之類的工作,順便說一句:

>>> 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.' 

但是,pickledill (和其他先進的串行化)將無法在任何類型的直接依賴於蟒蛇FrameType,就像一臺發電機:

>>> 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