pylance-release icon indicating copy to clipboard operation
pylance-release copied to clipboard

Overriding `__getattribute__` messes up utility of "Go to Definition"

Open zduvall opened this issue 1 year ago • 2 comments

Environment data

  • Language Server version:
    • Pylance language server 2023.12.1 (pyright a78e2b10)
  • OS and version:
    • darwin x64 (MacOS 14.0 (23A344))
  • Python version (& distribution if applicable, e.g. Anaconda):
    • Python 3.11.3
  • python.analysis.indexing: true
  • python.analysis.typeCheckingMode: off

Code Snippet

The empty comment lines are there for spacing to help demonstrate what happens with "Go to Definition".

class Test:

    def method(self):
        'Some method'
        pass

    #
    #
    #
    #
    #


    def __getattribute__(self, __name: str) -> Any:
        return super().__getattribute__(__name)


t = Test()

t.method()

Hovering over method is able to find the correct method/docstring:

Screenshot 2024-01-30 at 9 27 53 AM

However, "Go to Definition" takes me to __getattribute__:

Screenshot 2024-01-30 at 9 27 46 AM

Repro Steps

  1. Override __getattribute__
  2. Attempt using "Go to Definition"

Expected behavior

Be taken to the method/attribute with the corresponding name

Actual behavior

Taken to __getattribute__ method

Logs

Nothing of note:

2024-01-30 09:40:06.045 [info] [Info  - 9:40:06 AM] (43355) Heap stats: total_heap_size=127MB, used_heap_size=121MB, total_physical_size=127MB, total_available_size=3970MB, heap_size_limit=4096MB

zduvall avatar Jan 30 '24 14:01 zduvall

are you saying it goes to __getattributes__? I believe it shows both method and __getattributes__ and let you select where you go right?

image

this behavior is by design for __getattributes__ since it gets called regardless of whether attribute of the name exist or not.

but it seems it is a bug we do same for __getattr__ which should be only called when there is no attribute of the same name

heejaechang avatar Jan 30 '24 21:01 heejaechang

[Edited] ** ignore this part, we work as expected. I forgot to add (Base) to class Test

it looks like when we have this

from typing import Any

class Base:
    def __getattribute__(self, __name: str) -> Any:
        return super().__getattribute__(__name)

class Test:

    def method(self):
        'Some method'
        pass

    #
    #
    #
    #
    #


    


t = Test()

t.method()

go to def on method doesn't show __getattributes__ in the Base. that looks like a bug as well. we should include it except the one in object.__getattributes__ **

like overridden operator such as __add__, we want to make sure user knows some magic is injected over the normal behavior.

heejaechang avatar Jan 30 '24 22:01 heejaechang