-
-
Notifications
You must be signed in to change notification settings - Fork 375
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
Convenience decorators for promoting functions to attrs-compatible validators #1257
Comments
Thank you! ❤️
Oof man, this is a topic that's almost as old as attrs: #146 Giving up on my hopes and dreams of my youth, I guess we could replicate here something we've done to However, skimming your example you seem to have a much bigger need for customization? |
Ah I see. I had a look through that but have to admit I didn't read far enough to see the exact parallels. You've thought about it much more than me, so happy to close this and let you work it out elsewhere!
Not necessarily. If there was a built in way to do this in atttrs, I'd probably just use that. Because I wrote it myself, I added some extra info so I got slightly more verbose error messages, but ultimately it just boils down to what you discussed above, except in reverse I guess. I.e. rather than attrs doing the wrapping automatically, it would just provide a utility so users could explicitly 'upcast' their own functions if they wanted. That would mean you don't have to modify the attrs API as it stands, but could provide a convenient way for people to work around this problem if they want (rather than rolling their own solution and getting it wrong multiple times, like I did :)). |
That's not what I meant at all – as you can see I've been thinking about it for 7 years and never came up with anything good. Given PEP 712 (converters for dataclass transforms) and #1267 – I don't think the unification will ever happen.
I think this could be made to fit the approach in #1267 by introducing a |
I have some code I use for this, been considering adding it as a PR def validate_bool_func(bool_func) -> Callable:
"""
Validate the value using a custom boolean function.
Args:
bool_func: The boolean function to apply to the value.
Returns:
Callable: A validation function.
Raises:
TypeError: If the provided boolean function is not callable.
"""
if not isinstance(bool_func, Callable):
raise TypeError("provided boolean function must be callable")
def _(instance, attribute, value) -> None:
if not bool_func(value):
raise ValueError(
f"{attribute.name} does not pass {bool_func.__name__},"
f" received {value}. "
)
return _ example tests from my custom validators here: @pytest.mark.parametrize(
"val_func, inputs, expectation",
[
(
validate_bool_func(np.isnan),
np.nan,
does_not_raise(),
),
(
validate_bool_func(np.isnan),
1,
pytest.raises(ValueError),
),
],
)
def test_validate_bool_func(val_func, inputs, expectation):
@attr.define
class TestClass:
attrib: list = attr.ib(validator=[val_func])
with expectation:
TestClass(inputs) |
Hi there,
First, thanks for an amazing project! Words can't express how much attrs has changed my programming career for the better.
I have found that I often write some validation function which has to check something about some value. In most cases, the inbuilt validators are perfect, in some I still have to write something custom and that is where the question begins. For example, let's say I had some validation function like the below:
This is nice, because the function only takes in one value, which makes it easy to rationalise and re-use in the code in non-attrs contexts if needed. If I want to use it in attrs, as far as I can tell (and please correct me if I need to rtfd), I have two options.
The first is to add
instance
andattribute
as args to my function, e.g.This feels a bit off, because instance and attribute aren't used in the function. It is also confusing if you use it in a non-attrs context, because you have to call it as
check_weird_constraint(_, _, value)
.The other option is to write a wrapper that applies purely for the attrs context, e.g.
The second option feels better, but you end up having heaps of functions floating around.
So, my question, would there be any interest in including some convenience decorators in attrs to help with this situation? In some projects I have done, I have used the code below. I'd be happy to contribute a PR here if it that's of any interest
Details
The text was updated successfully, but these errors were encountered: