-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Type annotate CallSpec2 #6724
Type annotate CallSpec2 #6724
Conversation
for arg, val in zip(argnames, valset): | ||
self._checkargnotcontained(arg) | ||
valtype_for_arg = valtypes[arg] | ||
getattr(self, valtype_for_arg)[arg] = val |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to tweak the code here a bit, mypy can't understand getattr
. I also think it's better to avoid it in general.
To show that it is safe, I used Literal
here and in the source below Metafunc._resolve_arg_value_types
.
6fc55b9
to
ca0d1cd
Compare
self.params[arg] = val | ||
elif valtype_for_arg == "funcargs": | ||
self.funcargs[arg] = val | ||
else: # pragma: no cover |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Small tip, no need to change)
When I encounter these situations where we have a fixed number of if/elifs and an else clause as an error, I opt to have an explicit else: clause for the last choice:
if valtype_for_arg == "params":
self.params[arg] = val
elif valtype_for_arg == "funcargs":
self.funcargs[arg] = val
else: # pragma: no cover
assert False, "Unhandled valtype for arg: {}".format(valtype_for_arg)
Becomes:
if valtype_for_arg == "params":
self.params[arg] = val
else:
assert valtype_for_arg == "funcargs", "Unhandled valtype for arg: {}".format(valtype_for_arg)
self.funcargs[arg] = val
It is shorter and avoids having to write a pragma: nocover
😁
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion!
There is actually a reason why I prefer the form I wrote -- it allows to perform exhaustiveness checking. Consider for example that a new value is added to the valtype_for_arg
Literal type. Then ideally, mypy would raise an error if I didn't remember to add a case for it in the conditional.
For enums, this is already possible, see python/mypy#5818. In my own code I rely on this greatly.
For Literals, this is not yet supported by mypy, but hopefully will be in the future: python/mypy#6366
Regarding to no cover
, WDYT about adding assert False
to the coverage exclude_lines
list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise NotimplementedError()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think an assert is more appropriate than NotimplementedError
for this. assert means "internal assumption broken", while NotimplementedError
might imply "not implemented intentionally" which is not the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see it more like "might be implemented later", like you've decribed it yourself ("a new value is added").
But then maybe lets add ^\s*raise AssertionError\b
to the exclude list? I think it is good to be explicit here, to not ignore any assert 0
, but your assert False
might work for this also already.
Extracted from #6717.