Stateful mode filtering a lot with one_of(Bundle, Bundle) #2078
Considering the following statemachine:
from hypothesis.stateful import Bundle, RuleBasedStateMachine, rule from hypothesis.strategies import text class StateMachine(RuleBasedStateMachine): Things = Bundle("things") Stuff = Bundle("stuff") StuffAndThings = Things | Stuff @rule(target=Things, name=text()) def create_thing(self, name): return name @rule(target=Stuff, name=text()) def create_stuff(self, name): return name @rule(item=StuffAndThings) def do(self, item): return TestStateMachine = StateMachine.TestCase
However if I replace
So using a
I guess there is a good reason about this, but I couldn't find anything in the doc about this.
As a matter of fact I didn't expect Hypothesis to drop examples without explicitly using
Do you think it would make sens to document those two behaviors ?
The text was updated successfully, but these errors were encountered:
I've not looked into this in detail, but my guess based on knowing how the code works would be that the following is what's happening:
If this is what's happening, there's a two part fix available:
However this has a significant problem: The way the code for empty strategies currently works assumes that emptiness doesn't change once it's been established. That would no longer be the case, so we'd have to make some non-trivial internal refactorings to how that information is computed and accessed.
I think the behaviour with Bundles is just a bug so we should fix it rather than document it. It would probably be worth clarifying that examples can be invalid for all sorts of internal reasons even without an explicit filter or assume though, yeah.
Actually this is very easy to work around.
We can add a method:
def available(self, data): """Returns whether this strategy can *currently* draw any values.""" return not self.empty
Then individual strategies (currently just
@DRMacIver Thanks a lot for the quick&complete answer ;-)
I've created PR #2079 which implement your suggestion, it indeed greatly reduce the number of rejected items !
bundle = Bundle('foo') assert not bundle.available() bundle.add(42) assert bundle.available()
But I don't think we can directly do that (need a
As a related problem, currently-empty non-Bundle strategies may also have some problems related to changes over time. Consider the following:
In : from hypothesis.strategies import * In : LS =  In : s = deferred(lambda: sampled_from(LS)) In : s Out: deferred(lambda: sampled_from(LS)) In : s.is_empty HypothesisDeprecationWarning: sampled_from() with nothing to sample is deprecated and will be an error in a future version. It currently returns `st.nothing()`, which if unexpected can make parts of a strategy silently vanish. Out: True In : LS.append(1) In : s.is_empty Out: True In : s.example() Unsatisfiable: Unable to satisfy assumptions of hypothesis example_generating_inner_function. In : s.wrapped_strategy Out: sampled_from() In : s.wrapped_strategy.example() Unsatisfiable: Unable to satisfy assumptions of hypothesis example_generating_inner_function.
So I suspect that while a quick patch is worthwhile, we will need a deeper set of changes to fix the underlying issue.