2017-09-07 14 views
0

pythonのすべてのバージョン(27,33,34,35,36およびpypy)で動作するはずのPythonライブラリのテストを行っています。私のテストでは、datetimeライブラリを嘲笑しています。それらをすべて私がpypyで実行した場合を除いて動作します(これは以前の太字の理由を参照してください)。最後の行はFalse返す全てのPythonのバージョンでpypyでdatetimeライブラリを擬似すると、2つの模擬オブジェクトを比較するときにTypeErrorが発生する

import mock 
import datetime as dtl 
mk = mock.Mock(wraps=dtl.datetime) 
p = mock.patch('datetime.datetime', mk) 
p.start() 
from datetime import datetime 
d1 = datetime.now() 
d2 = datetime.now() 
print d1 == d2 

はここでトラブル私がいるためMCVEです。 pypyでは最後の行はスロー:

>>>> d1 == d2 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/pypy/lib_pypy/datetime.py", line 1764, in __eq__ 
    if isinstance(other, datetime): 
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types 

私は問題を理解しようとしているpypyのソースコードを掘り、そしてなぜ地球上でそれと他のPythonのバージョン間の違いがある、と私は以下のが見つかりました:

# Comparisons of datetime objects with other. 

def __eq__(self, other): 
    if isinstance(other, datetime): 
     return self._cmp(other) == 0 
    elif hasattr(other, "timetuple") and not isinstance(other, date): 
     return NotImplemented 
    else: 
     return False 

この種の意味があります。 datetimeクラスは今度はMockオブジェクトです。そして、pythonは、isinstanceの2番目の引数が型になると主張しています。 Neato。

は、だから私は datetimeのCPythonとの実装を見て決めた、と驚き驚き:

# Comparisons of datetime objects with other. 

def __eq__(self, other): 
    if isinstance(other, datetime): 
     return self._cmp(other, allow_mixed=True) == 0 
    elif not isinstance(other, date): 
     return NotImplemented 
    else: 
     return False 

同じ正確な検証がここで行われ、まだそれが何か¯\_(ツ)_/¯は発生しません。

私はこれのpython 2.7で起こることを追加します:

  1. はなぜ地球上で、それはCPythonのために働くん:

    >>> d = datetime.now() 
    >>> d 
    datetime.datetime(2017, 9, 7, 9, 31, 50, 838155) 
    >>> d == d 
    True 
    >>> datetime 
    <Mock id='139788521555024'> 
    >>> isinstance(d, datetime) 
    Traceback (most recent call last): 
        File "<stdin>", line 1, in <module> 
    TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types 
    

    私は苦労してる2つの質問がありますか?

  2. どのように私は、これは__eq__またはその他の魔法の方法を再実装することなく動作するような方法でDateTimeオブジェクトを模擬することができます:)
  3. 多くの義務が

答えて

1

これはPythonの実際の問題で、なぜisinstanceofを使用するのが悪い習慣であるかという良い例です。

解決策は模擬ではなく、むしろdatetime.datetimeから継承するクラスで修正することです。しかし、datetimeから継承し、実際のdatetimeクラスに基づいてタイプをチェックしたいので、isinstanceチェックをオーバーライドして、実際のクラスにする必要があります。

import datetime as dtl 
import mock 

real_datetime_class = dtl.datetime 

class DatetimeSubclassMeta(type): 
    """Datetime mock metaclass to check instancechek to the real class.""" 

    @classmethod 
    def __instancecheck__(mcs, obj): 
     return isinstance(obj, real_datetime_class) 

class BaseMockedDatetime(real_datetime_class): 
    """Mock class to cover datetime class.""" 

MockedDatetime = DatetimeSubclassMeta('datetime', 
             (BaseMockedDatetime,), 
             {}) 

p = mock.patch('datetime.datetime', MockedDatetime) 
p.start() 


from datetime import datetime 
d = datetime.now() 

isinstance(d, datetime) 
0

、それはおそらく、PyPyにはCPythonにCで実装されているdatetime、そして純粋なのpythonで行う必要があり、いくつかの微妙なPythonクラスオブジェクトと組み込みCオブジェクトの違い。