-
-
Notifications
You must be signed in to change notification settings - Fork 367
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
Poor error message/type for validators.in_ with a string #382
Comments
What is the actual problem here? I don't think it's fair to expect in_ to also type check? I think you want s = attr.ib(validator=[attr.validators.instance_of(str), attr.validators.in_('abc')]) ? |
I think the request is for something like: def __call__(self, inst, attr, value):
if value not in self.options:
try:
raise ValueError(
"'{name}' must be in {options!r} (got {value!r})"
.format(name=attr.name, options=self.options, value=value)
)
except Exception as e:
raise AssertionError(
"in_ validator for attribute {attr} raised exception for value {value}: {error}"
.format(attr=attr, value=value, error=e)
) |
Almost - the idea is that if I'd write this as follows, and would be happy to open a PR if that would be helpful 😄 def __call__(self, inst, attr, value):
try:
if value not in self.options:
raise ValueError(
"'{name}' must be in {options!r} (got {value!r})"
.format(name=attr.name, options=self.options, value=value)
)
except Exception:
raise ValueError(
"'{name}' must be in {options!r} "
"(got {value!r}, which caused an internal error)"
.format(name=attr.name, options=self.options, value=value)
) |
The contract for validators isn't super clear in the docs, but I don't see anything that says that I do agree that the a better error message would be useful, but I'd definitely include the original exception text. |
Uh yeah there is absolutely no contract about what kind of exceptions are raised by validators and I’d even argue that changing it could be backward incompatible. 🤔 |
I think it might make some sense for us to advise that certain exceptions are used, but I wouldn't go farther than that. Otherwise, every validator would have to wrap a try/except around it's body, which could be a best practice, but seems like a lame thing to require. Which leaves us with: should we do better than the above error message. I notice I wrapped the try/except in my example around the wrong code (oops). Lemme try again with a different suggestion: def __call__(self, inst, attr, value):
try:
in_options = value in self.options
except TypeError as e:
in_options = False
if not in_options:
raise ValueError(
"'{name}' must be in {options!r} (got {value!r})"
.format(name=attr.name, options=self.options, value=value)
) I don't think trying to catch all exceptions is necessarily more correct, but we can definitely say that a non-string object isn't in the provide bucket (that happens to be a string) of options. Since that bucket isn't required to contain objects of a homogenous type, I returning |
I guess I would accept a PR in this case. |
__contains__
behaves a little weirdly for strings, but I still think this error could be improved.Obvious options would be to catch exceptions and re-raise something with a clearer error message, and/or to deprecate use of strings as the collection here.
Found in attrs=18.1.0 while working on HypothesisWorks/hypothesis#954.
The text was updated successfully, but these errors were encountered: