-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Python: properly support keyword only arguments #3362
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
Conversation
Currently keyword-only parameters are not handled properly :(
I want to ensure we handle when only _some_ parameters have default/annotations
The result is the same, but `getAKeywordOnlyArg` is the method used everywhere else in the code.
Default values for positional arugments follow a rule, so if an argument has a default value, later positional arguments must also have default values. The database only stores the actual default values, and nothing about the arguments that doesn't have default values. This turns out to be a major problem for Argument.getKwDefault(i), since default values for keyword-only arguments doesn't have the same rule. So if you know there is one default value, you can't tell if it is associated with `foo` or `bar`, as in the examples below: ``` def a(*, foo=None, bar): pass def b(*, foo, bar=None): pass ```
This commit is based on a change to the extractor
Works like a charm ;)
I tested that the upgrade script works properly,
|
Woops, seems like I forgot the part about 2. Run a Stats/CPP job and update ql repo with the results. 🤔 will have to figure out if it is required for this change or not 🤔 |
Our internal docs say that:
Since this upgrade only renumbers a few items in the I think it's probably worth it to look into whether we should update the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really good. I think we need to think a bit more about how we might improve the interface with the generated AST classes. I'm leaning more towards wrapping most of the methods in there so that we get more control over naming and documentation. But that's beyond the scope of this PR. 🙂
python/upgrades/f635b392038a494915307f913657cd3058f9b476/py_exprs.ql
Outdated
Show resolved
Hide resolved
newidx = | ||
max(int i | | ||
exists(Parameter_ param | param = callable.getInnerScope().getKwonlyarg(i) | | ||
param.getLocation().getStartLine() < expr.getLocation().getStartLine() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ordering bit seems mildly magical. An explanatory comment is probably in order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I tried to explain in 5a18b08 :)
Co-authored-by: Taus <tausbn@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I think this looks good. Time to scrutinise the internals. 🔍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the explanatory comment! This looks good to me! 🙂
Main purpose of this PR:
To properly support keyword-only parameters. That is done in c508e89.
Secondary purpose:
Properly support default values for keyword-only parameters. That is done in c5e14f5 and the updates to the database.
Default values for positional arguments follow a rule, so if an argument has a default value, later positional arguments must also have default values.
The database only stores the actual default values, and nothing about the arguments that doesn't have default values.
This turns out to be a major problem for
Argument.getKwDefault(i)
, since default values for keyword-only arguments doesn't have the same rule. So if you know there is one default value, you can't tell if it is associated withfoo
orbar
, as in the examples below:This PR (and corresponding internal extractor change) fixes this, by making
Argument.getKwDefault(i)
return the default value for keyword-only parameteri
(instead of the i'th default for a keyword-only parameter).Argument.getDefault
is changed in the same manner to keep consistency.