You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Within the ranges module we use typing.cast in some places to cast the return type. For example, here when taking the intersection of two FiniteRanges we cast the return type as FiniteRange. This will make the returned value appear as a FiniteRange to type checkers (e.g. mypy) and to anyone inspecting the type annotations. However, if you actually make a runtime isinstance check then this will fail - the returned value is actually not a FiniteRange but simply a Range.
r1=FiniteRange(D(0), D(10))
r2=FiniteRange(D(5), D(15))
# mypy is fine with this (because that is what the type annotations say!)intersection: Optional[FiniteRange[D]] =r1&r2# Sanity checkassertintersectionisnotNone# However the below line of code will fail!assertisinstance(intersection, FiniteRange)
Why does this matter?
It's confusing and can potentially lead to bugs.
Example: In Optimise FiniteDatetimeRange __lt__, intersection and union #187 we introduced an optimisation to the intersection and union methods of FiniteDatetimeRange. However, these optimisations rely on an isinstance check. If a range is lying about its type then this can't work.
Proposed solution
I believe that we are misusing cast here (and in other places in the ranges module). I believe the intention has been to use cast here to avoid any performance penalty. However, the cast is simply not true! cast should only be used when we can be certain that the cast type is actually correct.
Remove this use of cast (and likely the others in the ranges module). Instead, actually instantiate a FiniteRange.
base_intersection=super().intersection(other)
ifbase_intersectionisNone:
returnNonereturnFiniteRange(
# This use of cast is okay - we can be sure that `base_intersection.start` is actually of type `T`.cast(T, base_intersection.start)
cast(T, base_intersection.end)
)
The text was updated successfully, but these errors were encountered:
Problem
Within the ranges module we use
typing.cast
in some places to cast the return type. For example, here when taking the intersection of twoFiniteRange
s we cast the return type asFiniteRange
. This will make the returned value appear as aFiniteRange
to type checkers (e.g. mypy) and to anyone inspecting the type annotations. However, if you actually make a runtimeisinstance
check then this will fail - the returned value is actually not aFiniteRange
but simply aRange
.Why does this matter?
FiniteDatetimeRange
. However, these optimisations rely on anisinstance
check. If a range is lying about its type then this can't work.Proposed solution
cast
here (and in other places in the ranges module). I believe the intention has been to usecast
here to avoid any performance penalty. However, the cast is simply not true!cast
should only be used when we can be certain that the cast type is actually correct.FiniteRange
.The text was updated successfully, but these errors were encountered: