0

Assume this simple case: (reposted and lightly edited from the Hypothesis mailing list)

@dataclass
class A:
   names: list[str]
   ages: dict[str, float]

How could I write a strategy which generates objects of type A but with the restriction that the keys in the ages dict are taken from the list names (which are, in turn, randomly generated)?

Zac Hatfield-Dodds
  • 2,455
  • 6
  • 19
  • 1
    `dataclass` doesn't seem like a good fit. Is the intent that both of those containers are mutable, and that changes in one should be reflected in the other? Are they both auto-generated when an `A` is constructed and then frozen at that point? Is one of them the source of truth and the other derived from it? – Samwise Dec 23 '22 at 01:48

1 Answers1

0

There are a couple of ways to generate inter-dependent data, of which I'd usually recommend reaching for @st.composite strategies - the imperative approach is a bit more verbose, but easy to read and works even for really complicated situations. Here:

@st.composite
def a_instances(draw):
    ages = draw(st.dictionaries(st.text(), st.floats()))
    names = list(ages)  # could add elements, shuffle, etc here too.
    return A(names=names, ages=ages)

Or we could exploit the simplicity of the A class, and use a simpler but harder-to-extend strategy like:

a_instances = st.dictionaries(st.text(), st.floats()).map(
    lambda ages: A(names=list(ages), ages=ages
)

As Samwise notes though, this is a pretty strange example and I'd personally try tidying up the code a bit then using @st.composite.

Zac Hatfield-Dodds
  • 2,455
  • 6
  • 19