New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incompatible Sequence types generated after register_type_strategy() #3767
Comments
I'd argue it's correct for namedtuples are a bit weird, because they have the same typing as the above scenario, but aren't treated the same by users. As in, nobody thinks of a namedtuple as a generic sequence. I PR'd a special handling of namedtuple here #3768. Though in retrospect, I should have waited for opinions from maintainers on this issue first to make sure it was wanted - apologies! |
Thanks for making a PR for this! I agree, considering just the type signatures, these are type-compatible. Making namedtuple types not eligible for Another case is using a type-annotated namedtuple like this: from typing import NamedTuple
class Thing(NamedTuple):
foo: int In the current released hypothesis, this is eligible for I wonder if |
Ah, I was a bit rushed earlier and forgot about this. When I was working around this issue to fix my tests, one thing I tried was registering a function to conditionally generate the strategy only when required, e.g: class Thing(NamedTuple):
foo: int
def get_thing_strategy(target: type[Any]) -> st.SearchStrategy[Thing]:
if target == Thing:
return st.builds(Thing)
# Opt out of proving a strategy for this target
return st.nothing()
st.register_type_strategy(Thing, get_thing_strategy) But this is treated by Hypothesis as if no strategy exists for the type of the empty = ", ".join(repr(s) for s in strategies if s.is_empty)
if empty or not strategies:
raise ResolutionFailed(
f"Could not resolve {empty or thing} to a strategy; "
"consider using register_type_strategy"
) Is this a bug? Shouldn't this only fail if all strategies are empty, not if any is empty? If this were possible, it would basically allow what I was wondering in my comment above, about limiting the registration of strategies to certain base types. |
This works as a hacky workaround to conditionally register a strategy: def get_thing_strategy(target: type[Any]) -> st.SearchStrategy[Thing]:
if target == Thing:
return st.builds(Thing)
return st.none().filter(lambda x: False) |
I think we could support Pragmatically, dropping subtypes of
The catch is that not all subclasses of I'm not sure what we should do about this, but it seems likely that it's currently mishandled in at least some situations 😥. One important mitigation is that we resolve abstract classes to their nearest concrete subclasses, not any subclass - e.g. providing instances of Dog for abstract Animal, not instances of Poodle or Labrador or whatever. Probably we should continue to ignore this until someone reports a practical problem! |
Cool, I like the sound of that. |
That would be lovely - thanks Hal! |
A
from_type(Sequence[XXX])
strategy is able to generate instances of classes unrelated toXXX
that are Sequence subtypes registered withregister_type_strategy()
.Probably best explained with an example. Both of these tests fail:
I ran into this after upgrading from hypothesis
6.68.2
to6.87.3
. In my case I had some strategies registered with namedtuple types which started getting generated for unrelated strategies. It also happens forSequence
subclasses, but only if they are not specifying a generic type.It seems to be related to #2951.
hypothesis/hypothesis-python/src/hypothesis/strategies/_internal/types.py
Line 326 in 8a379f3
try_issubclass(k, thing)
thinks theThing
namedtuple is a subclass ofSequence[Other]
.I can see this is a rather hairy problem looking at the code!
The text was updated successfully, but these errors were encountered: