-
Notifications
You must be signed in to change notification settings - Fork 151
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
Remove Optional
from a few places
#210
Conversation
…ions_component_id_2.md Signed-off-by: Antony Milne <[email protected]>
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 double-checking again! 🚀
What you wrote makes a lot of sense and I agree that this is probably still a bit naughty, but better than the other alternative 👍
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 like this change, and I think the reasoning is sound although of course in a perfect world this would not be necessary
Co-authored-by: Li Nguyen <[email protected]> Signed-off-by: Antony Milne <[email protected]>
Description
Following a discussion in #190 (comment) about whether or not we should have
Optional
in our field type hints e.g. forNavigation
, I've made a PR to implement what I think should be our preferred solution.I agree with everything @huong-li-nguyen said in #190 (comment), which means that whether or not we specify
Optional
has no effect at runtime - it's purely of interest for mypy.The problem we have is that mypy (correctly) interprets
navigation: Optional[Navigation] = None
as giving navigation the typeUnion[None, Navigation]
. In reality if it'sNone
then we populate it straight away in a validator, so we know that it can't beNone
, but mypy doesn't know this unless you tell it explicitly.There are various ways to perform this type narrowing e.g.
assert self.navigation is not None
, usingcast
or worse just putting intype: ignores
. All of these would work but litter the code quite a bit. See e.g. theassert
solution in https://mypy.readthedocs.io/en/stable/kinds_of_types.html#optional-types-and-the-none-type.On the other hand, if we set
navigation: Navigation = None
then mypy interprets the type (probably incorrectly tbh...) asNavigation
with no option ofNone
. The catch here is that we need to dotype: ignore[assignment]
or mypy will complain at this point that you're assigningNone
to something that can't beNone
.So the choice is between doing something a bit naughty at point of assignment vs. doing something annoying every time the optional field is consumed. Since the field is defined once but consumed multiple times, overall I think it's best to do the naughty thing at point of assignment so that all consuming code can be cleaned up.
Following this and #189 we now have what I would deem an acceptably small number of
type: ignore
s in our codebase, although when we do bump to pydantic v2 I suspect this will need to tackled again...I deliberately haven't changed e.g.
value: Optional[List[float]] = None
inRangeSlider
. The reason for this is:None
as a genuine value rather than a sentinel value that gets replaced at runtimetype: ignore
s or other annoyances currently, and since the reason for this change is purely to appease type checking it doesn't seem worth spending more time on... but in theory if we think it's better to change these also then we could do so.
Checklist
Types of changes
Notice
I acknowledge and agree that, by checking this box and clicking "Submit Pull Request":