Let's say I want to generate a list of users, but I want each user to be unique by id and email independently, not unique by the pair of properties.
For example, the strategy should not generate [{'id': 1, 'email': '[email protected]'}, {'id': 1, 'email': '[email protected]'}], because they both have the same id. This might occur if I were to do the following:
strategies.lists(_user_generator(), min_size=1, max_size=2, unique_by=lambda x: (x['id'], x['email']))
What I would really like is something along the lines of:
strategies.lists(_user_generator(), min_size=1, max_size=2, unique_by=[lambda x: x['id'], lambda x: x['email']])
Am I missing a common approach here, or is something like this needed as a new feature?
Sounds like a useful feature request to me! Tagged as enhancement because it's upgrading an existing strategy rather than adding a new one.
You could currently approximate this by generating two unique lists, or by filtering, but that will be inefficient to shrink or to generate respectively. (check out the @composite docs if you don't mind that)
For anyone who wants to implement this: check out hypothesis.searchstrategies.collections.UniqueListStrategy, and think about using a list of key functions. As a design point I think we should stick to a single "seen" set for all the key functions; this is a slightly stronger uniqueness property in that it avoids possible collisions - for example unique_by=(get_first_element, get_last_element) nothing can be generated with a last element that is the same as any other last or first element. It's much easier to relax this later than to tighten the uniqueness constraint!
Then thread that back through to the public interface. For validation, I think we'll insist on a single callable or a tuple of two or more callables, without allowing lists (because of mutation).
Thank you, it sounds like @composite will be helpful.
I can have a go at this one
Most helpful comment
I can have a go at this one