wrapt icon indicating copy to clipboard operation
wrapt copied to clipboard

PyCharm warnings about unfilled parameters

Open denizdogan opened this issue 5 years ago • 9 comments

This library amazing, thank you for making it.

However, one minor issue when I use it in PyCharm (and probably other linters)...

I've written this simple decorator:

@wrapt.decorator
def serialize_response(wrapped, _instance, args, kwargs):
    return serialize_object(wrapped(*args, **kwargs))

Then I use it like this:

    @serialize_response # <-- warnings appear here
    def get_address(self, id_number: str, customer_ip: str) -> dict:

The warning looks like this:

Parameter unfilled

Is there any way to get around this warning without prefixing the method with # noinspection PyArgumentList?

denizdogan avatar May 16 '19 13:05 denizdogan

That is odd. Any idea what mechanism PyCharm uses to introspect the method details? The wrapt package uses various tricks so normal Python introspection functions work fine. It looks like PyCharm is not using normal methods for introspecting functions. Can you add trying using inspect.getfullargspec() on the function to see what it produces.

GrahamDumpleton avatar May 17 '19 20:05 GrahamDumpleton

@GrahamDumpleton This is the output (formatted by me):

FullArgSpec(
    args=['wrapped', '_instance', 'args', 'kwargs'], 
    varargs=None, 
    varkw=None,
    defaults=None, 
    kwonlyargs=[], 
    kwonlydefaults=None, 
    annotations={},
)

I honestly don't know how PyCharm performs introspection :/

denizdogan avatar May 19 '19 09:05 denizdogan

What exact version of Python is this, and what distribution if not the original CPython from the PSF?

When inspect.getfullargspec() is applied to the decorated function, you should get the original arguments. Eg.

>>> import wrapt
>>> @wrapt.decorator
... def wrapper(wrapped, instance, args, kwargs): return wrapped(*args, **kwargs)
...

>>> import inspect

>>> @wrapper
... def func(a, b, **c): pass
...

>>> inspect.getfullargspec(func)
FullArgSpec(args=['a', 'b'], varargs=None, varkw='c', defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})

GrahamDumpleton avatar May 19 '19 11:05 GrahamDumpleton

@GrahamDumpleton My apologies, I thought you meant getfullargspec of the decorator itself (wrapper in your example), doh. Obviously you meant the wrapped function, here is the correct output:

FullArgSpec(
    args=['self', 'id_number', 'customer_ip'],
    varargs=None,
    varkw=None,
    defaults=None,
    kwonlyargs=[],
    kwonlydefaults=None,
    annotations={
        'return': <class 'dict'>,
        'customer_ip': <class 'str'>,
        'id_number': <class 'str'>
    }
)

This is the full Python version information:

Python 3.5.7 (default, Apr 10 2019, 14:22:52)
[GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.46.3)] on darwin

(If it matters, I built and installed this Python version using pyenv.)

This is the detailed PyCharm information:

PyCharm 2019.1.2 (Professional Edition) Build #PY-191.7141.48, built on May 7, 2019 JRE: 11.0.2+9-b159.56 x86_64 JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o macOS 10.14.4

denizdogan avatar May 19 '19 12:05 denizdogan

Yes, but PyCharm is possibly looking at what you did. The highlighting is actually on the decorator and not the wrapped function, and getsignature() doesn't actually return a signature that would make sense in that situation. I'll need to do some testing and have a think about it.

GrahamDumpleton avatar May 19 '19 12:05 GrahamDumpleton

Would you possibly be able to install the develop branch on this repo and try it.

pip install https://github.com/GrahamDumpleton/wrapt/archive/develop.zip

I have made a change which means the decorator created should return as signature that of the original decorator function, and not the wrapper.

FullArgSpec(args=['wrapper', 'enabled', 'adapter'], varargs=None, varkw=None, defaults=(None, None, None), kwonlyargs=[], kwonlydefaults=None, annotations={})

This should hopefully satisfy what the linters are looking for.

Note that the develop branch does include another change for an odd issue related to garbage collection. If you see any really strange issues that affect your program, including crashes, let me know.

GrahamDumpleton avatar May 21 '19 01:05 GrahamDumpleton

Unfortunately, using the develop.zip archive, PyCharm still complains with the same warning:

image

With this code:

import wrapt

@wrapt.decorator
def wrapper(wrapped, _instance, args, kwargs):
    return wrapped(*args, **kwargs)

@wrapper
def foo():
    pass

...getfullargspec(wrapper) returns, as you promised:

FullArgSpec(args=['wrapper', 'enabled', 'adapter'], varargs=None, varkw=None, defaults=(None, None, None), kwonlyargs=[], kwonlydefaults=None, annotations={})

...and getfullargspec(foo) returns:

FullArgSpec(args=[], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})

So I'm not sure what is really going on here? It's the same behavior in Python 3.5.6 and 3.7.3. I've tried searching for an explanation of how PyCharm introspects these things, to no avail :(

denizdogan avatar May 21 '19 10:05 denizdogan

I believe I'm seeing a similar issue with https://github.com/microsoft/pyright/.

import wrapt


@wrapt.decorator
def foo(wrapper, instance, args, kwargs):
    return wrapper(*args, **kwargs)


@foo   <---- error   Arguments missing for parameters "instance", "args", "kwargs"
def bar(x: int) -> int:
    return x

Here are a couple of related discussions: https://github.com/microsoft/pyright/issues/413, https://github.com/microsoft/pyright/issues/774, which seem to suggest that wrapt.decorator could be typed in a way that improves the situation. I'm no expert, what do you think, @GrahamDumpleton ?

indigoviolet avatar Mar 30 '22 22:03 indigoviolet

Experiencing the same as well with Pylance with the general example

Arguments missing for parameters "instance", "args", "kwargs"Pylance[reportGeneralTypeIssues](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportGeneralTypeIssues)
(function) def debug_stats(
    wrapped: (...) -> Any,
    instance: Any,
    args: Any,
    kwargs: Any
) -> ((...) -> Any)

asciifaceman avatar May 19 '23 18:05 asciifaceman