0

I want to generate a list of dicts where all the dicts have the same set of keys.

import json
import hypothesis
from hypothesis import strategies as st


@st.composite
def list_of_dicts_with_keys_matching(draw,dicts=st.dictionaries(st.text(), st.text())):
    mapping = draw(dicts)

    return st.lists(st.fixed_dictionaries(mapping))

@hypothesis.given(list_of_dicts_with_keys_matching())
def test_simple_json_strategy(obj):
    dumped = json.dumps(obj)
    assert isinstance(obj, list)
    assert json.dumps(json.loads(dumped)) == dumped

TypeError: Object of type LazyStrategy is not JSON serializable

How can I fix this?

Edit: Second attempt:

import string

import pytest
import hypothesis
import hypothesis.strategies as st


@st.composite
def list_of_dicts_with_keys_matching(draw, keys=st.text(), values=st.text()):
    shared_keys = draw(st.lists(keys, min_size=3))
    return draw(st.lists(st.dictionaries(st.sampled_from(shared_keys), values, min_size=1)))


@hypothesis.given(list_of_dicts_with_keys_matching())
def test_shared_keys(dicts):
    assert len({frozenset(d.keys()) for d in dicts}) in [0, 1]


# Falsifying example: test_shared_keys(dicts=[{'': ''}, {'0': ''}])
Hatshepsut
  • 5,962
  • 8
  • 44
  • 80

1 Answers1

0

You are missing the draw(...) in return draw(st.lists(st.fixed_dictionaries(mapping))).

However, this will lead you to the second problem - st.fixed_dictionaries takes a mapping of keys to strategies for values, but mapping here will be a Dict[str, str]. Perhaps:

@st.composite
def list_of_dicts_with_keys_matching(draw, keys=st.text(), values=st.text()):
    shared_keys = draw(st.lists(keys, min_size=3))
    return draw(st.lists(st.dictionaries(st.sampled_from(shared_keys), values)))

Update: the snippet above will draw varied keys from a shared set. For identical keys for all dicts, I'd write:

@st.composite
def list_of_dicts_with_keys_matching(draw, keys=st.text(), values=st.text()):
    shared_keys = draw(st.sets(keys))
    return draw(st.lists(st.fixed_dictionaries(
        {k: values for k in shared_keys}
    )))
Zac Hatfield-Dodds
  • 2,455
  • 6
  • 19
  • This answer doesn't quite work. For example, it produces `[{'': ''}, {'0': ''}]`, which don't have shared keys. – Hatshepsut May 30 '19 at 19:07