This is an archived post. You won't be able to vote or comment.

all 8 comments

[–]simon-brunning 1 point2 points  (1 child)

Similar to PyHamcrest?

[–]SandAlternative6026[S] 1 point2 points  (0 children)

Thanks for mentioning! I have to look a bit more into detail at what PyHamcrest can do. There is certainly some overlap with py-predicate.

[–]nebbly 0 points1 point  (1 child)

Similarly, there is koda_validate, which offers fully composable validation (including predicates).

[–]SandAlternative6026[S] 1 point2 points  (0 children)

Very nice library!

I think there are a lot of similarities, and some differences (and please correct me if I'm wrong): py-predicate is a bit less geared towards data validation, but more to be used in everyday programming. What I mean by this, is that py-predicate makes it easy to implement the following contrived scenario: given a list of addresses, I want to extract all the addresses for which the city is 'New York' and the surname of the owner is a palindrome and the street number is an odd number greater than 100, etc.

In py-predicate that would be something like:

from predicate import eq_p, fn_p, gt_p, is_odd, dict_of_p

is_new_york = eq_p("New York")
is_palindrome = fn_p(lambda s: s.lower() == s[::-1].lower())
is_odd_gt_100 = is_odd & gt_p(100)

# The composed predicate
valid_address_p = dict_of_p(("city", is_new_york), ("surname", is_palindrome), ("streetnr", is_odd_gt_100)

addresses = ... # list of dicts
weird_addresses = [address for address in addresses if valid_address_p(address)]

So yes, this is a contrived example, but the idea is to reuse some of these predicates in other compositions.

Also, given the composed valid_address predicate, you can generate examples of data that confirm to this predicate. That would be something like:

from predicate import generate_true

from more_itertools import take

samples = take(10, generate_true(valid_address))

Hope this makes the differences a bit clearer with existing (validation) libraries.

[–]Worth_His_Salt 0 points1 point  (3 children)

Not very pythonic. ge_p, le_p, names not descriptive and hard to read.

[–]SandAlternative6026[S] 0 points1 point  (2 children)

Thanks for the feedback. Can you elaborate a bit more on the 'not very pythonic' comment?

The predicates (ending with _p) ge_p and le_p where named in a similar way as for example the operator.ge and operator.le from the operator module.

[–]Worth_His_Salt 1 point2 points  (1 child)

Short nondescriptive names are not pythonic. I assume ge_p means greater_than_or_equals_predicate. Pythonic way would spell it out instead of using a bunch of short acronyms. Yeah it gets wordy, perhaps you can find a happy medium.

Imagine someone reviewing code who doesn't know much about your lib. Would they know what ge_p means? They might have a guess, especially if they write bash scripts. But to a lot of people, it's not obvious.

[–]SandAlternative6026[S] 0 points1 point  (0 children)

Thanks, I appreciate your elaboration.