nutti / fake-bpy-module

Fake Blender Python API module collection for the code completion.
MIT License
1.37k stars 97 forks source link

BlendData getitem returns wrong type #234

Closed Andrej730 closed 4 months ago

Andrej730 commented 4 months ago

Example for BlendDataObjects(same for the other BlendData types):

from typing import assert_type
import bpy
obj = bpy.data.objects["Cube"]
# "assert_type" mismatch: expected "Object" but received "Any"
assert_type(obj, bpy.types.Object)

I assume it happens because BlendData inherit from two classes - bpy_struct and bpy_props_collection[Object].

image

Though bpy_props_collection[Object].__getitem__ should cover this case: image

bpy_struct also has __getitem__ implemented and it overrides the bpy_props_collection method: image

nutti commented 4 months ago

@Andrej730 Is __getitem__ not needed for bpy_struct?

nutti commented 4 months ago

@Andrej730

If not needed, you can modify below entry directly to fix this issue. https://github.com/nutti/fake-bpy-module/blob/1527d132e8e79974644ccac400d33fbb1d56dcf5/src/mods/common/analyzer/append/bpy.types.mod.rst?plain=1#L82

nutti commented 4 months ago

@Road-hog123

Can this issue solve by deleting __getitem__ from bpy_struct?

Road-hog123 commented 4 months ago

@nutti

I think removing all three methods from bpy_struct would mitigate this and related issues, but then classes that inherit only from bpy_struct wouldn't have them. Putting bpy_prop_collection first would be a better solution if bpy_struct must be inherited from.

Andrej730 commented 4 months ago

bpy_struct has __getitem__ in the actual bpy, so I guess removing it indeed could lead to issues (can't pinpoint any specific though). But it's kind of weird since actual bpy.data.objects is of type bpy_prop_collection...

bpy.types.bpy_struct.__getitem__
# <slot wrapper '__getitem__' of 'bpy_struct' objects>

bpy.types.BlendDataObjects.__getitem__
# <slot wrapper '__getitem__' of 'bpy_struct' objects>

bpy.data.objects
# <bpy_collection[3], BlendDataObjects>

type(bpy.data.objects).__getitem__
# <slot wrapper '__getitem__' of 'bpy_prop_collection' objects>

bpy.data.objects.__getitem__
# <method-wrapper '__getitem__' of bpy_prop_collection object at 0x00000243197EE700>
nutti commented 4 months ago

@Road-hog123 @Andrej730

Thank you for your comments. It helps me a lot. It is difficult to search the complete solution because of Blender internal tweaks. I think removing __getitem__ from bpy_struct makes better user experiences. What do you think?

Andrej730 commented 4 months ago

I think removing __getitem__ from bpy_struct makes better user experiences.

We can try since this one is easy to revert either way if we'll find some edge case for this.

Road-hog123 commented 4 months ago

@nutti

Unless all methods are removed from bpy_struct it will continue to override or incorrectly add methods when collections inherit from it (bpy.data.objects receives get() and pop() from bpy_struct when it should only receive get() from bpy_prop_collection).

nutti commented 4 months ago

@Road-hog123

Ah, I could understand your idea. Should we reverse inheritance order like this?

class BlendDataObjects(bpy_struct, bpy_prop_collection[Object]):
class BlendDataObjects(bpy_prop_collection[Object], bpy_struct):
Road-hog123 commented 4 months ago

Should we reverse inheritance order like this?

class BlendDataObjects(bpy_prop_collection[Object], bpy_struct):

@nutti That's what I tried to suggest yesterday—it would fix most issues (inheriting from subscripted classes before plain classes (a[b], c) seems like a good idea in general).

The only part this won't fix is autocomplete for non-existent attributes like bpy.data.objects.pop(), which can only be fixed by not inheriting from bpy_struct at all.

nutti commented 4 months ago

This issue is now fixed.