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
How to use with recursive namedtuple? #3608
Comments
I found the following in another issue (#3026): class RecursiveClass:
def __init__(self, value: int, next_node: typing.Optional["SomeClass"]):
assert value > 0
self.value = value
self.next_node = next_node
st.register_type_strategy(
RecursiveClass,
st.builds(RecursiveClass, value=st.integers(min_value=1)) # next_node inferred from type annotation
)
build_strategy_for_some_class = st.builds(
SomeClass,
value=st.integers(min_value=1),
next_node=st.none() | st.deferred(lambda: st.from_type(SomeClass)),
)
st.register_type_strategy(SomeClass, build_strategy_for_some_class) But I don't know how I can make it work for namedtuples, with non-optional arguments. For the example I posted above it would make sense to use I can change the namedtuple to use the from collections import namedtuple
TreeNode = namedtuple('TreeNode', ('value', 'children'), defaults=(0, None)) Then try the following: recursive_tree_strat = st.recursive(
# note the missing argument
st.builds(TreeNode, st.integers()),
lambda children: st.tuples(children, children),
max_leaves=100
)
class TestRecursiveDataNamedtuples(unittest.TestCase):
@given(x=recursive_tree_strat)
def test_can_be_compound(self, x):
if not isinstance(x, int):
assert isinstance(x, TreeNode) But this also results in an error:
Hypothesis does not seem to realize, that there is a default value for the namedtuple, which it could use to make a leaf. |
You seem to be unsure about the type of |
But that is exactly what I want to do. Not limiting, how deep the recursion can go in the code of the data structure (in this case a named tuple), but limit it through the means of hypothesis for the tests. For tests I can assume some maximum depth for a realistic case, but I cannot assume that in the actual code, otherwise I make the data structure less general purpose and arbitrarily limited in nature. In general there are often data structures, especially trees, which can theoretically have arbitrary depth and I cannot limit them ahead of time in their own code. That would defeat their purpose.
I don't know how I would do so. The children of a Is it generally impossible with |
class TreeNode(typing.NamedTuple):
value: int
children: "typing.Collection[TreeNode]" # base case is an empty collection
st.from_type(TreeNode) # this should work fine You must have a base case where it's possible for a |
Could you leave this open, until I had time to verify, that the code you posted actually does, what I am looking for? @Zac-HD |
I would like to make a recursive strategy for a namedtuple, to use in a unit test, but could not find a way yet how to do this properly with hypothesis:
And the test code I have so far:
In the test case I want to be able to use the strategy like any other strategy:
All examples I found so far are with simple values, not compound ones, but in a tree I need children, which are of the very structure, that I am trying to create a strategy for. How can this be achieved? Maybe I should not be using
builds
?If I run the tests without the ellipsis in place, I get of course the following error:
because the
TreeNode
namedtuple is missing an argument, because I did not specify anotherargs
in the call tobuilds
. However, I am not sure what I can put there instead.If I call
builds
with an additonalTreeNode
, of course that is also wrong, becauseTreeNode
is not a strategy, but the class of the value I want to create. I get the following error then:EDIT-1:
When using
from_type(TreeNode)
as argument, I also get an error, back to missing 2 arguments, probably for an internal call done byfrom_type
(?):Gets the following error:
The text was updated successfully, but these errors were encountered: