Mark Lakewood
Mark Lakewood

Reputation: 133

Python Hypothesis: How to compose generators that are dependent on each other?

I have a generator using python Hypothesis like the following:

@st.composite
def generate_network_fault_only(draw):
    fault = {
        "impaired": st.just(True),   # need to detect if all faults are None to switch this back.
        "limit": draw(NetworkFaultGen.generate_limit()),
        "delay": draw(NetworkFaultGen.generate_delay()),
        "loss_random": draw(NetworkFaultGen.generate_loss_random()),
        "corrupt": draw(NetworkFaultGen.generate_corrupt()),
        "duplicate": draw(NetworkFaultGen.generate_duplicate()),
        "reorder": draw(NetworkFaultGen.generate_reorder()),
        "rate": draw(NetworkFaultGen.generate_rate())
    }

    return draw(st.fixed_dictionaries(fault))

Each of the functions above returns something like:

@st.composite
def generate_reorder(draw):
    """
    This must only happen if delay is applied
    """
    return st.one_of(st.fixed_dictionaries(
              {"percent": st.integers(min_value=0, max_value=100),
               "correlation": st.integers(min_value=0, max_value=100),
               "distance": st.integers(min_value=0)}),st.none())

I have a dependency between the reorder value and the delay value in that reorder can only be specified if delay is not None.

I am not sure how to accomplish this. Filtering seems to run into performance issues. And at this point in the code the delay value isnt a concrete value yet.

Upvotes: 5

Views: 1439

Answers (2)

Chris
Chris

Reputation: 1455

I have a dependency between the reorder value and the delay value in that reorder can only be specified if delay is not None. I am not sure how to accomplish this.

In your composite strategy you can simply conditionally specify a reorder only if delay is present.

@composite
def generate_network_fault_only(draw):
  fault = {
       "impaired": st.just(True),  
        "limit": draw(NetworkFaultGen.generate_limit()),
        "delay": draw(NetworkFaultGen.generate_delay()),
        "loss_random": draw(NetworkFaultGen.generate_loss_random()),
        "corrupt": draw(NetworkFaultGen.generate_corrupt()),
        "duplicate": draw(NetworkFaultGen.generate_duplicate()),
        "rate": draw(NetworkFaultGen.generate_rate())
  }

  if fault['delay']:
    fault['reorder'] = draw(generate_reorder())
  return fault

Upvotes: 0

DRMacIver
DRMacIver

Reputation: 2315

If you want delay to be specified only once globally per example (i.e. fixed to a single value each time given calls your test function, but potentially different between different calls), you could use shared to do it? https://hypothesis.readthedocs.io/en/latest/data.html#hypothesis.strategies.shared

i.e. if you do something like delay = shared(my_base_strategy, key='network.delay') then all other strategies which depend on delay can just draw from it and get a single consistent value.

Upvotes: 1

Related Questions