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

Decorators confuse E1120 analysis #259

Closed
pylint-bot opened this issue Jun 10, 2014 · 17 comments · Fixed by #2926
Closed

Decorators confuse E1120 analysis #259

pylint-bot opened this issue Jun 10, 2014 · 17 comments · Fixed by #2926
Labels
Bug 🪲 Checkers Related to a checker

Comments

@pylint-bot
Copy link

Originally reported by: the mulhern (BitBucket: the_mulhern)


Here's the example:

#!python


def decorator(f):

    def new_func(junk=None):
        f(2, junk=junk)

    return new_func

@decorator
def junk1(param, junk=None):
    print("%s" % junk)

def main():
    junk1(junk=2)

The analysis reports
"No value passed for parameter 'param' in function call (no-value-for-parameter)"
This is incorrect, since the actual function being called is the new_func manufactured
by the decorator, and that function does not require the parameter 'param'.

You can work around this by giving param a default value, (which will never be used).


@pylint-bot
Copy link
Author

Original comment by Sylvain Thénault (BitBucket: sthenault, GitHub: @sthenault?):


Removing version: 1.1 (automated comment)

@pylint-bot
Copy link
Author

Original comment by Scott Stanton (BitBucket: scott_stanton_veeva):


This is very annoying if you are using the Google AppEngine ndb decorators like ndb.transactional(). The decorator is generated by @utils.decorator which converts a function to a decorator. E1120 ends up thinking the decorator arguments are required, so every use of @transactional() generates an error.

@pylint-bot
Copy link
Author

Original comment by Claudiu Popa (BitBucket: PCManticore, GitHub: @PCManticore):


Yeah, ideally this would have been fixed a long time ago. There are many issues and not enough manpower to provide a fix in time for all of them. The only promise I can make right now is that I'll try to target this for fixing in 1.6, since 1.5 is almost ready for launching.

@pylint-bot pylint-bot added Bug 🪲 Checkers Related to a checker labels Dec 9, 2015
@PCManticore PCManticore added this to the 2.0 milestone May 9, 2016
@deckar01
Copy link

Comments moved here from #207.


Here is a minimal example to reproduce the issue:

def helper(fun):
    def wrapper(b):
        return fun('helper', b)
    return wrapper

@helper
def simple(a, b):
    print a, b

simple('test')

E: 10, 0: No value for argument 'b' in function call (no-value-for-parameter)


Here is the same example with the decorator replaced with method composition:

def helper(fun):
    def wrapper(b):
        return fun('helper', b)
    return wrapper

def hard(a, b):
    print a, b

simple = helper(hard)

simple('test')

No errors


To prove that pylint is not simply skipping the signature checking for method composition:

def helper(fun):
    def wrapper(b):
        return fun('helper', b)
    return wrapper

def hard(a, b):
    print a, b

simple = helper(hard)

simple('helper?', 'test')

E: 11, 0: Too many positional arguments for function call (too-many-function-args)


The issue is not that pylint is incapable of inferring the signature of generated methods, but rather that pylint lacks the instruction to treat decorators as the composed functions they are.


This issue seems to stem from the core AST module leaving it up to the consumer to resolve the signature produced by applying the decorator_list.

It should be sufficient to detect when a function node has decorators and substitute it with the return value(s?) of the first decorator.

I think it would be generally useful to determine the resulting signature in asteroid. Maybe an attribute like external_args?

@eight04
Copy link

eight04 commented Mar 25, 2017

Thanks @deckar01. Converting the decorator to simple function call did work.

@iddan
Copy link

iddan commented Oct 14, 2017

Any change with this?

@davidjlloyd
Copy link

This is still broken as of pylint 1.7.1, astroid 1.5.3.

@maozguttman
Copy link

What about following code (based on deckar01's above example) which gives false positive too-many-function-args error:

def helper(fun):
    def wrapper(a, b, *args, **kwargs):
        print "helper wrapper: a={}".format(a)
        return fun(b, *args, **kwargs)
    return wrapper

@helper
def simple(b, c):
    print "simple: b={} c={}".format(b, c)

simple('argentina', 'brazil', 'china')

Its output is:

helper wrapper: a=argentina
simple: b=brazil c=china

And pylint false positive error is:

E: 11, 0: Too many positional arguments for function call (too-many-function-args)

Thanks,
Maoz

@Niedzwiedzw
Copy link

Is this still broken?

@PCManticore PCManticore removed this from the 3.0 milestone Apr 25, 2018
@PCManticore
Copy link
Contributor

Hey folks, this issue is not fixed yet, as it is still opened. I can't promise when it's going to be fixed though.

@ricardosalinase
Copy link

pls, do something, this is ugly for the code

@isaacnorman82
Copy link

This is marked as closed but I still see this issue in pylint 2.5.3. Am I missing something?

@tmattha
Copy link

tmattha commented Jul 15, 2020

I am still having a false-positive with hypothesis.strategies.composite in pylint 2.5.3.
Error message: No value for argument 'draw' in function call
see also: https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies

@bionicles
Copy link

bionicles commented Jul 19, 2020

Same issue with

def curry(fun):
    return partial(partial, fun)
@curry
def look(path, data):
    for key in path:
        data = data[key]
    return data
@curry
def look_paths(paths, data):
    return parallel(look(path) for path in paths)(data)
# No value for argument 'data' in function call pylint(no-value-for-parameter)

@UncleOwen
Copy link

@isaacnorman82 @tmattha @bionicles
Have a look at #2926.

@bionicles
Copy link

bionicles commented Jan 21, 2021

this made me rage, but i finally fixed it, so here's a fix for the next frustrated person
gotta make sure your curry function only accepts 1 argument... recursive currying is no bueno
src.ramda

import functools
def curry(arity):
    """build a function to curry functions with N args"""

    def currier(func):
        """curry a function with a pre-determined number of arguments"""

        def curried(*args, **kwargs):
            if len(args) + len(kwargs) >= arity:
                return func(*args, **kwargs)

            def curried_more(*args2, **kwargs2):
                return curried(*(args + args2), **dict(kwargs, **kwargs2))

            functools.update_wrapper(curried_more, func)
            return curried_more

        functools.update_wrapper(curried, func)
        return curried

    return currier


curry2 = curry(2)
curry3 = curry(3)
curry4 = curry(4)

/pylintrc

[MASTER]
ignore=archive,data,scripts,art
jobs=2

[TYPECHECK]
signature-mutators=src.ramda.curry,src.ramda.curry2,src.ramda.curry3,src.ramda.curry4

@hippo91
Copy link
Contributor

hippo91 commented Jan 30, 2021

This issue become too messy. I lock it. If you are facing a problem that looks similar please open a new issue that refers this one if necessary.

@pylint-dev pylint-dev locked as too heated and limited conversation to collaborators Jan 30, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug 🪲 Checkers Related to a checker
Projects
None yet
Development

Successfully merging a pull request may close this issue.