Closed JonathanPlasse closed 4 months ago
I think the input type should be mathutils.Vector | typing.Sequence[float]
—perhaps this could be defined as a type alias, thereby giving it a nice clean name?
object.location = range(1, 4)
presently raises a false error because range
is a Sequence
that is neither list
nor tuple
. Sequence[float]
on its own is insufficient as mathutils.Vector
is missing several Sequence
methods.
The same should probably be done for Euler
, Quaternion
and Matrix
.
@JonathanPlasse
Tweaking each attribute is a bit costly for the generation.
Is it possible to absorb the change in mathutils.Vector
or bpy.types.bpy_prop_array
?
I have to check, but I think it should be possible to use descriptors to absorb the change in mathutils.Vector
.
Here is the version using descriptor.
This absorbs the change in mathutils.Vector
.
The only inconvenient is that when assigning a tuple to Vector
, any size of float tuple is accepted, but this is already the case when assigning a Vector
of different size.
class Vector:
def __get__(self, instance, owner) -> "Vector": ...
def __set__(self, instance, value: "Vector | list[float] | tuple[float, ...]") -> None: ...
class Object:
# Old
# location: typing.Union[typing.List[float], typing.Tuple[float, float, float], "mathutils.Vector"]
# New
location: Vector
# The following code is valid with both Pyright and MyPy
o = Object()
o.location = (0, 4, 5)
v: Vector = o.location
That looks like a promising solution! 😄
I wonder if it would be worth defining a Protocol for Vector-like input? o.location = range(3)
and o.location = np.array((0, 4, 5))
should also type check okay.
any size of float tuple is accepted
Sequence length checking is not within the scope of a type checker, so this is not an issue. 👍
Using Iterable[float]
should work.
That looks like a promising solution! 😄
I wonder if it would be worth defining a Protocol for Vector-like input?
o.location = range(3)
ando.location = np.array((0, 4, 5))
should also type check okay.any size of float tuple is accepted Sequence length checking is not within the scope of a type checker, so this is not an issue. 👍
I will try implementing this.
Using
Iterable[float]
should work.
Ah, but (n for n in range(3))
is an Iterable
that should not type check okay—__len__
is required. 😉
Sequence[float]
then.
Using
Iterable[float]
should work.Ah, but
(n for n in range(3))
is anIterable
that should not type check okay—__len__
is required. 😉
Sequence[float]
then.
Ah, but np.array
is not a Sequence
😢
Perhaps I will dive into the source code and work out exactly what methods are required—__len__
and __getitem__
for sure.
So a protocol with __len__
and __getitem__
should be enough.
This protocol would only be used as allowed type when setting a property.
Related issue with other mathutils types: Color, Euler, Quaternion, Matrix.
from mathutils import Matrix, Vector, Euler
import bpy
obj: bpy.types.Object = None
m = obj.matrix_world
v = Vector()
# Operator "@" not supported for types "list[list[float]] | tuple[tuple[float, float, float, float], tuple[float, float, float, float], tuple[float, float, float, float], tuple[float, float, float, float]] | Matrix" and "Vector"
# Operator "@" not supported for types "list[list[float]]" and "Vector"
# Operator "@" not supported for types "tuple[tuple[float, float, float, float], tuple[float, float, float, float], tuple[float, float, float, float], tuple[float, float, float, float]]" and "Vector"
new_v = m @ v
quat = obj.rotation_quaternion
# Operator "@" not supported for types "list[float] | tuple[float, float, float, float] | Quaternion" and "Vector"
# Operator "@" not supported for types "list[float]" and "Vector"
# Operator "@" not supported for types "tuple[float, float, float, float]" and "Vector"
new_v = quat @ v
# Cannot access attribute "rotate" for class "list[float]"
# Cannot access attribute "rotate" for class "tuple[float, float, float]"
obj.rotation_euler.rotate(Euler())
mat: bpy.types.Material = None
# Cannot access attribute "hsv" for class "list[float]"
# Cannot access attribute "hsv" for class "tuple[float, float, float]"
mat.specular_color.hsv
@JonathanPlasse @Road-hog123
Thank you for diving into the solution!
BTW, do you want to contribute this issue? Fortunately, this can be fixed by tweaking mod file. https://github.com/nutti/fake-bpy-module/blob/master/src/mods/common/analyzer/append/mathutils.mod.rst?plain=1
Perhaps, we may need to modify data_type_refiner.py
.
I would like to work on it.
@JonathanPlasse
Thanks. Sure, go ahead.
The
Object.location
can be assigns aVector
,list[float]
, ortuple[float, float, float]
but only ever returnsVector
. The type hints should reflect this. More generally, allVector
properties should be using this.What motivated this change? When getting the value of
Object.location
the type deduced by Pyright is the union instead ofVector
. This means that in a typed codebase, every get on a vector property need to be cast.The following code would now be valid with Pyright.
This is the proposed changes for
Object.location
. All other vector properties could use the same typing.In the current state, Mypy raise an error for the getter, with this change it would raise an error on the setter because of its limited support for setters.
In the current state, Pyright raise an error for the getter, with this change it would not raise any error.