🐞
eventでリストを表示させる
Hypothesisを使って次のような形で event
で自作クラスのインスタンスのリストを表示させたいとする。
from dataclasses import dataclass
from hypothesis import event, given
from hypothesis.strategies import builds, integers, lists, text
@dataclass(frozen=True)
class Foo:
x: int
y: str
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __hash__(self):
return hash((self.x, self.y))
@given(lists(builds(Foo, integers(), text()), max_size=4))
def test_foo(l):
event(l)
すると次のようにevent
はunhashableなオブジェクトは扱えない旨のエラーメッセージが出る。
self = ConjectureData(VALID, 1 bytes, frozen), event = []
def note_event(self, event: Hashable) -> None:
assert isinstance(self.events, set)
> self.events.add(event)
E TypeError: unhashable type: 'list'
というわけで、リストのサイズも小さいのでタプルにすることでhashableにする。
@given(lists(builds(Foo, integers(), text()), max_size=4))
def test_foo(l):
t = tuple(l)
event(t)
しかし今度は次のようなエラーで落ちる。
self = <WeakKeyDictionary at 0x105c17430>, key = ()
def __getitem__(self, key):
> return self.data[ref(key)]
E TypeError: cannot create weak reference to 'tuple' object
../../../.pyenv/versions/3.10.4/lib/python3.10/weakref.py:416: TypeError
本当はコードの中を見たほうがいいと思うんだけど、event
でタプルを受け取るなんて普通にやることだと思うから、ワークアラウンドがあるんじゃなかと思って、Stack Overflowに質問してみた。
すると、Hypothesisのリードメンテナーから回答が得られて、これはバグとして処理するとのこと。一応ワークアラウンドとして 'str' で対応することが提案された。
@given(lists(builds(Foo, integers(), text()), max_size=3))
def test_foo(l):
s = str(l)
event(s)
これは無事に実行できた。
============================== Hypothesis Statistics ===============================
test_foo.py::test_foo:
- during generate phase (0.15 seconds):
- Typical runtimes: 0-1 ms, ~ 79% in data generation
- 100 passing examples, 0 failing examples, 26 invalid examples
- Events:
* 9.52%, [Foo(x=0, y='')]
* 2.38%, [Foo(x=-37, y='')]
* 1.59%, [Foo(x=-88, y='\x0ff')]
* 1.59%, [Foo(x=22754, y=''), Foo(x=514, y=' ')]
* 1.59%, [Foo(x=22754, y='4 ')]
* 0.79%, [Foo(x=-108, y='^!P\U000a3497\U000e0e57\x84Óñtª\x88\x95\U000a788dLE'), Foo(x=-109, y='\x94`§O\U00045d57'), Foo(x=18695, y='\U000e40840Xë£\U00019dfcì\U0004dd2e²÷¢\U0004f407×\U0007a1bd\x9eÖ')]
(...略...)
* 0.79%, [Foo(x=8720, y='ý'), Foo(x=-4009, y='`\U000c599cÉ\U000ff3f6\U0004e5e2Ç\U00014b48\U000aee32Ï')]
* 0.79%, []
- Stopped because settings.max_examples=100
一応リードメンテナーがバグだと言っていたので、upstreamにもissueとして報告しておいた。
追記 (2022-07-04)
本記事の内容はupstream(ver 6.48.3)で対応されたのでobsoleteになりました。今後はhashableを投げれば普通に表示されます。
Discussion