Skip to content
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

Filtering kwargs #2707

Closed
mristin opened this issue Dec 19, 2020 · 1 comment
Closed

Filtering kwargs #2707

mristin opened this issue Dec 19, 2020 · 1 comment
Labels
question not sure it's a bug? questions welcome

Comments

@mristin
Copy link
Contributor

mristin commented Dec 19, 2020

I am looking now into how to rewrite contracts using the **kwargs -> fixed_dictionaries() and consequential .filter(.) chain. This is relevant for multi-argument preconditions which need to be transformed into multi-argument filters.

I suppose the filter function would now need to take only a single argument, the whole dictionary? Consider the following example where we have a function taking two integers, x and y, and preconditions x < y and x + y < 1000, transformed into a strategy:

(
fixed_dictionaries({'x': integers(), 'y': integers()})
    .filter(lambda d: d['x'] < d['y'])
    .filter(lambda d: d['x'] + d['y'] < 1000)
)

In my case (icontract), the conditions are lambdas whose arguments are directly tied to the function argument names (such as lambda x, y: x < y). If I want to transform them into Hypothesis filters programatically, I would need to parse them, rewrite them and recompile them on the fly. This is quite complex, and tedious to program as naming conflicts need to be avoided (e.g., the precondition might use the global variable d which I intended for the name of the dictionary argument).

Are there maybe some other ways that already exist in Hypothesis that such preconditions can be filtered and that it will be easy for Hypothesis to optimize them in the future (once the optimization on multi-argument filters has been implemented)?

For example, using a separate function would most probably impede the optimization:

def filterKwargs(
    kwargs: Mapping[str, Any], 
    condition: Callable[..., Any],
    condition_args: List[str]
) -> Any:
    return condition(
        **{
            arg_name: kwargs[arg_name] 
            for arg_name in condition_args
          }
    )

which gives us the transformtion:

(
fixed_dictionaries({'x': integers(), 'y': integers()})
    .filter(lambda d: filterKwargs(d, lambda x, y: x < y, ['x', 'y'])
    .filter(lambda d: filterKwargs(d, lambda x, y: x + y < 1000, ['x', 'y'])
)

(This issue is related to the issue #2701.)

@Zac-HD Zac-HD added the question not sure it's a bug? questions welcome label Dec 20, 2020
@Zac-HD
Copy link
Member

Zac-HD commented Dec 20, 2020

I suppose the filter function would now need to take only a single argument, the whole dictionary?

That's correct, and e.g. .filter(lambda d: d['x'] < d['y']) is an idiomatic example - though as you say, difficult to automatically construct.

Are there maybe some other ways that already exist in Hypothesis that such preconditions can be filtered and that it will be easy for Hypothesis to optimize them in the future (once the optimization on multi-argument filters has been implemented)?

We don't (yet?) have any such function, and at this stage my advice would be to ignore any rewriting concerns and just get it working nicely for you. For example you can use inspect.signature(condition).parameters instead of a condition_args argument... we'll work out the integration later, and can always special-case the icontract idiom if that's what it takes 🙂

(closing because I don't think there's any action for this issue which isn't already covered by #2701)

@Zac-HD Zac-HD closed this as completed Dec 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question not sure it's a bug? questions welcome
Projects
None yet
Development

No branches or pull requests

2 participants