Skip to content
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

get_signature() for decorated function faulty with manipulated parameter list #1894

Open
vbrdev opened this issue Nov 21, 2022 · 4 comments
Open

Comments

@vbrdev
Copy link

vbrdev commented Nov 21, 2022

I can reproduce #1791 with Jedi 0.18.1 and Python 3.10.3 using a different approach:

import functools

def f(x: int, y: float):
    pass

def do_wrap():
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        x = args[0]
        y = args[1]
        args = (x,y)
        return f(*args, **kwargs)
    return wrapper

fails = do_wrap()
fails(1, 2.0) # f(*args)

So basically the problem occurs when passing different parameters (e.g. different arg object) to f() within wrapper(). So calling the function like that f(x, y) also fails.

Motivation: I have a decorator that corrects some args of my wrapped functions (based on different rules) before calling its implementation.

@vbrdev vbrdev changed the title get_signature() for decorated function fails with manipulated parameter list get_signature() for decorated function faulty with manipulated parameter list Nov 21, 2022
@vbrdev
Copy link
Author

vbrdev commented Nov 22, 2022

I also noticed that with decorators the Jedi response time for signature requests is terribly slow. I therefore activated debug output and saw that heavy parsing processes are taking place. I also noticed multiple warnings like this:

warning: not possible to resolve wrappers found <Class: Iterable@168-171>

Unfortunately the response time is also slow when keeping arguments as they are:

import functools

def f(x: int, y: float):
    pass

def do_wrap2():
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        return f(*args, **kwargs)
    return wrapper

works = do_wrap2()
works( # f(x: int, y: float)

For functions without decorators everything is smooth like it should.

@davidhalter
Copy link
Owner

How are you using Jedi? In Interpreter mode? How slow is it in the simple example you gave? 100ms? 1s? 10s?

@vbrdev
Copy link
Author

vbrdev commented Nov 22, 2022

I found the time consuming function:

project = jedi.Project(path, load_unsafe_extensions=True, sys_path=sys.path)
script = jedi.Script(code, project=project)
sig = script.get_signatures(row, column) # <Signature: index=0 f(*args)>
# The following params call takes ~2.4 seconds
params = sig.params # [<ParamName name='args', description='param *args'>]

Please note the returned incorrect signature content. I tested the same example code in our Jedi Interpreter environment. The response is super fast and the returned signature is correct: f(x: int, y: float).

With the following code the time of sig.params drops from ~2.4 to 0.0002 seconds and the right signature is returned:

import functools

def f(x: int, y: float):
    pass

def do_wrap():
    @functools.wraps(f)
    def wrapper(x: int, y: float):
        return f(x, y)
    return wrapper

works = do_wrap()
works() # f(x: int, y: float)

@davidhalter
Copy link
Owner

Not sure this is easily fixable without reducing support for a feature... :-/

Definitely also a case of #1059, I'm rewriting Jedi in Rust, where this kind of stuff should not be a problem. But it might take a few years to finish that...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants