This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: ast.FunctionDef sets a bad value for kw_defaults when keyword-only arguments present
Type: Stage: test needed
Components: Library (Lib) Versions: Python 3.3, Python 3.4
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: brett.cannon, daniel.urban, jcea
Priority: normal Keywords: 3.3regression

Created on 2012-11-23 22:40 by brett.cannon, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (3)
msg176260 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2012-11-23 22:40
When there are no keyword-only arguments, the value of kw_defaults for FunctionDef is []. But when keyword-only arguments are present with no default values, it becomes [None]. That's bad as every other value in FunctionDef has a default of [] when there is nothing of value there (currently you can trust that [None] means no default value as None isn't anything in the AST).


>>> ast.dump(ast.parse('def func(*, name):pass'))
"Module(body=[FunctionDef(name='func', args=arguments(args=[], vararg=None, varargannotation=None, kwonlyargs=[arg(arg='name', annotation=None)], kwarg=None, kwargannotation=None, defaults=[], kw_defaults=[None]), body=[Pass()], decorator_list=[], returns=None)])"

>>> ast.dump(ast.parse('def func(name):pass'))
"Module(body=[FunctionDef(name='func', args=arguments(args=[arg(arg='name', annotation=None)], vararg=None, varargannotation=None, kwonlyargs=[], kwarg=None, kwargannotation=None, defaults=[], kw_defaults=[]), body=[Pass()], decorator_list=[], returns=None)])"
msg176283 - (view) Author: Daniel Urban (daniel.urban) * (Python triager) Date: 2012-11-24 11:51
If I understand correctly, the invariant is that len(kw_defaults) == len(kwonlyargs). I think the reason is that the following is valid syntax (an argument without a default after one with a default):

>>> def f(*, a=0, b): pass
... 
>>>

And None is used as a placeholder in the kw_defaults list:
>>> ast.dump(ast.parse('def f(*, a=0, b): pass'))
"Module(body=[FunctionDef(name='f', args=arguments(args=[], vararg=None, varargannotation=None, kwonlyargs=[arg(arg='a', annotation=None), arg(arg='b', annotation=None)], kwarg=None, kwargannotation=None, defaults=[], kw_defaults=[Num(n=0), None]), body=[Pass()], decorator_list=[], returns=None)])"
>>>

So it seems to me, that this behavior is intentional. (Also, it works no differently in 3.2.)
msg176289 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2012-11-24 14:25
Ah, I see it now. I didn't realize that we allowed people to define keyword-only arguments in any order they wanted in terms of default values, allowing interleaving of default and non-default values. So this is correct, just different from everything else.
History
Date User Action Args
2022-04-11 14:57:38adminsetgithub: 60749
2012-11-26 17:24:12jceasetstatus: open -> closed
resolution: not a bug
2012-11-26 17:23:44jceasetstatus: closed -> open
nosy: + jcea
resolution: not a bug -> (no value)
2012-11-24 14:25:16brett.cannonsetstatus: open -> closed
resolution: not a bug
messages: + msg176289
2012-11-24 11:51:17daniel.urbansetmessages: + msg176283
2012-11-24 08:10:17daniel.urbansetnosy: + daniel.urban
2012-11-23 22:40:46brett.cannoncreate