bpo-36540: PEP 570 -- Implementation (GH-12701)
This commit contains the implementation of PEP570: Python positional-only parameters. * Update Grammar/Grammar with new typedarglist and varargslist * Regenerate grammar files * Update and regenerate AST related files * Update code object * Update marshal.c * Update compiler and symtable * Regenerate importlib files * Update callable objects * Implement positional-only args logic in ceval.c * Regenerate frozen data * Update standard library to account for positional-only args * Add test file for positional-only args * Update other test files to account for positional-only args * Add News entry * Update inspect module and related tests
This commit is contained in:
parent
99fcc616d4
commit
8c77b8cb91
|
@ -22,13 +22,55 @@ async_funcdef: ASYNC funcdef
|
||||||
funcdef: 'def' NAME parameters ['->' test] ':' [TYPE_COMMENT] func_body_suite
|
funcdef: 'def' NAME parameters ['->' test] ':' [TYPE_COMMENT] func_body_suite
|
||||||
|
|
||||||
parameters: '(' [typedargslist] ')'
|
parameters: '(' [typedargslist] ')'
|
||||||
typedargslist: (tfpdef ['=' test] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] [
|
|
||||||
|
# The following definition for typedarglist is equivalent to this set of rules:
|
||||||
|
#
|
||||||
|
# arguments = argument (',' [TYPE_COMMENT] argument)*
|
||||||
|
# argument = tfpdef ['=' test]
|
||||||
|
# kwargs = '**' tfpdef [','] [TYPE_COMMENT]
|
||||||
|
# args = '*' [tfpdef]
|
||||||
|
# kwonly_kwargs = (',' [TYPE_COMMENT] argument)* (TYPE_COMMENT | [',' [TYPE_COMMENT] [kwargs]])
|
||||||
|
# args_kwonly_kwargs = args kwonly_kwargs | kwargs
|
||||||
|
# poskeyword_args_kwonly_kwargs = arguments ( TYPE_COMMENT | [',' [TYPE_COMMENT] [args_kwonly_kwargs]])
|
||||||
|
# typedargslist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs
|
||||||
|
# typedarglist = (arguments ',' [TYPE_COMMENT] '/' [',' [[TYPE_COMMENT] typedargslist_no_posonly]])|(typedargslist_no_posonly)"
|
||||||
|
#
|
||||||
|
# It needs to be fully expanded to allow our LL(1) parser to work on it.
|
||||||
|
|
||||||
|
typedargslist: (
|
||||||
|
(tfpdef ['=' test] (',' [TYPE_COMMENT] tfpdef ['=' test])* ',' [TYPE_COMMENT] '/' [',' [ [TYPE_COMMENT] tfpdef ['=' test] (
|
||||||
|
',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] [
|
||||||
|
'*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
|
||||||
|
| '**' tfpdef [','] [TYPE_COMMENT]]])
|
||||||
|
| '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
|
||||||
|
| '**' tfpdef [','] [TYPE_COMMENT]]] )
|
||||||
|
| (tfpdef ['=' test] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] [
|
||||||
'*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
|
'*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
|
||||||
| '**' tfpdef [','] [TYPE_COMMENT]]])
|
| '**' tfpdef [','] [TYPE_COMMENT]]])
|
||||||
| '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
|
| '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
|
||||||
| '**' tfpdef [','] [TYPE_COMMENT])
|
| '**' tfpdef [','] [TYPE_COMMENT])
|
||||||
|
)
|
||||||
tfpdef: NAME [':' test]
|
tfpdef: NAME [':' test]
|
||||||
varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
|
|
||||||
|
# The following definition for varargslist is equivalent to this set of rules:
|
||||||
|
#
|
||||||
|
# arguments = argument (',' argument )*
|
||||||
|
# argument = vfpdef ['=' test]
|
||||||
|
# kwargs = '**' vfpdef [',']
|
||||||
|
# args = '*' [vfpdef]
|
||||||
|
# kwonly_kwargs = (',' argument )* [',' [kwargs]]
|
||||||
|
# args_kwonly_kwargs = args kwonly_kwargs | kwargs
|
||||||
|
# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]]
|
||||||
|
# vararglist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs
|
||||||
|
# varargslist = arguments ',' '/' [','[(vararglist_no_posonly)]] | (vararglist_no_posonly)
|
||||||
|
#
|
||||||
|
# It needs to be fully expanded to allow our LL(1) parser to work on it.
|
||||||
|
|
||||||
|
varargslist: vfpdef ['=' test ](',' vfpdef ['=' test])* ',' '/' [',' [ (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
|
||||||
|
'*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
||||||
|
| '**' vfpdef [',']]]
|
||||||
|
| '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
||||||
|
| '**' vfpdef [',']) ]] | (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
|
||||||
'*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
'*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
||||||
| '**' vfpdef [',']]]
|
| '**' vfpdef [',']]]
|
||||||
| '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
| '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
||||||
|
|
|
@ -427,6 +427,7 @@ struct _excepthandler {
|
||||||
|
|
||||||
struct _arguments {
|
struct _arguments {
|
||||||
asdl_seq *args;
|
asdl_seq *args;
|
||||||
|
asdl_seq *posonlyargs;
|
||||||
arg_ty vararg;
|
arg_ty vararg;
|
||||||
asdl_seq *kwonlyargs;
|
asdl_seq *kwonlyargs;
|
||||||
asdl_seq *kw_defaults;
|
asdl_seq *kw_defaults;
|
||||||
|
@ -684,10 +685,11 @@ excepthandler_ty _Py_ExceptHandler(expr_ty type, identifier name, asdl_seq *
|
||||||
body, int lineno, int col_offset, int
|
body, int lineno, int col_offset, int
|
||||||
end_lineno, int end_col_offset, PyArena
|
end_lineno, int end_col_offset, PyArena
|
||||||
*arena);
|
*arena);
|
||||||
#define arguments(a0, a1, a2, a3, a4, a5, a6) _Py_arguments(a0, a1, a2, a3, a4, a5, a6)
|
#define arguments(a0, a1, a2, a3, a4, a5, a6, a7) _Py_arguments(a0, a1, a2, a3, a4, a5, a6, a7)
|
||||||
arguments_ty _Py_arguments(asdl_seq * args, arg_ty vararg, asdl_seq *
|
arguments_ty _Py_arguments(asdl_seq * args, asdl_seq * posonlyargs, arg_ty
|
||||||
kwonlyargs, asdl_seq * kw_defaults, arg_ty kwarg,
|
vararg, asdl_seq * kwonlyargs, asdl_seq *
|
||||||
asdl_seq * defaults, PyArena *arena);
|
kw_defaults, arg_ty kwarg, asdl_seq * defaults,
|
||||||
|
PyArena *arena);
|
||||||
#define arg(a0, a1, a2, a3, a4, a5, a6, a7) _Py_arg(a0, a1, a2, a3, a4, a5, a6, a7)
|
#define arg(a0, a1, a2, a3, a4, a5, a6, a7) _Py_arg(a0, a1, a2, a3, a4, a5, a6, a7)
|
||||||
arg_ty _Py_arg(identifier arg, expr_ty annotation, string type_comment, int
|
arg_ty _Py_arg(identifier arg, expr_ty annotation, string type_comment, int
|
||||||
lineno, int col_offset, int end_lineno, int end_col_offset,
|
lineno, int col_offset, int end_lineno, int end_col_offset,
|
||||||
|
|
|
@ -21,6 +21,7 @@ typedef uint16_t _Py_CODEUNIT;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
int co_argcount; /* #arguments, except *args */
|
int co_argcount; /* #arguments, except *args */
|
||||||
|
int co_posonlyargcount; /* #positional only arguments */
|
||||||
int co_kwonlyargcount; /* #keyword only arguments */
|
int co_kwonlyargcount; /* #keyword only arguments */
|
||||||
int co_nlocals; /* #local variables */
|
int co_nlocals; /* #local variables */
|
||||||
int co_stacksize; /* #entries needed for evaluation stack */
|
int co_stacksize; /* #entries needed for evaluation stack */
|
||||||
|
@ -102,7 +103,7 @@ PyAPI_DATA(PyTypeObject) PyCode_Type;
|
||||||
|
|
||||||
/* Public interface */
|
/* Public interface */
|
||||||
PyAPI_FUNC(PyCodeObject *) PyCode_New(
|
PyAPI_FUNC(PyCodeObject *) PyCode_New(
|
||||||
int, int, int, int, int, PyObject *, PyObject *,
|
int, int, int, int, int, int, PyObject *, PyObject *,
|
||||||
PyObject *, PyObject *, PyObject *, PyObject *,
|
PyObject *, PyObject *, PyObject *, PyObject *,
|
||||||
PyObject *, PyObject *, int, PyObject *);
|
PyObject *, PyObject *, int, PyObject *);
|
||||||
/* same as struct above */
|
/* same as struct above */
|
||||||
|
|
|
@ -80,9 +80,9 @@ class PythonValuesTestCase(unittest.TestCase):
|
||||||
continue
|
continue
|
||||||
items.append((entry.name.decode("ascii"), entry.size))
|
items.append((entry.name.decode("ascii"), entry.size))
|
||||||
|
|
||||||
expected = [("__hello__", 139),
|
expected = [("__hello__", 141),
|
||||||
("__phello__", -139),
|
("__phello__", -141),
|
||||||
("__phello__.spam", 139),
|
("__phello__.spam", 141),
|
||||||
]
|
]
|
||||||
self.assertEqual(items, expected, "PyImport_FrozenModules example "
|
self.assertEqual(items, expected, "PyImport_FrozenModules example "
|
||||||
"in Doc/library/ctypes.rst may be out of date")
|
"in Doc/library/ctypes.rst may be out of date")
|
||||||
|
|
|
@ -157,6 +157,7 @@ def _format_code_info(co):
|
||||||
lines.append("Name: %s" % co.co_name)
|
lines.append("Name: %s" % co.co_name)
|
||||||
lines.append("Filename: %s" % co.co_filename)
|
lines.append("Filename: %s" % co.co_filename)
|
||||||
lines.append("Argument count: %s" % co.co_argcount)
|
lines.append("Argument count: %s" % co.co_argcount)
|
||||||
|
lines.append("Positional-only arguments: %s" % co.co_posonlyargcount)
|
||||||
lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
|
lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)
|
||||||
lines.append("Number of locals: %s" % co.co_nlocals)
|
lines.append("Number of locals: %s" % co.co_nlocals)
|
||||||
lines.append("Stack size: %s" % co.co_stacksize)
|
lines.append("Stack size: %s" % co.co_stacksize)
|
||||||
|
|
|
@ -265,6 +265,7 @@ _code_type = type(_write_atomic.__code__)
|
||||||
# this might affected the first line number #32911)
|
# this might affected the first line number #32911)
|
||||||
# Python 3.8a1 3400 (move frame block handling to compiler #17611)
|
# Python 3.8a1 3400 (move frame block handling to compiler #17611)
|
||||||
# Python 3.8a1 3401 (add END_ASYNC_FOR #33041)
|
# Python 3.8a1 3401 (add END_ASYNC_FOR #33041)
|
||||||
|
# Python 3.8a1 3410 (PEP570 Python Positional-Only Parameters #36540)
|
||||||
#
|
#
|
||||||
# MAGIC must change whenever the bytecode emitted by the compiler may no
|
# MAGIC must change whenever the bytecode emitted by the compiler may no
|
||||||
# longer be understood by older implementations of the eval loop (usually
|
# longer be understood by older implementations of the eval loop (usually
|
||||||
|
@ -273,7 +274,7 @@ _code_type = type(_write_atomic.__code__)
|
||||||
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
|
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
|
||||||
# in PC/launcher.c must also be updated.
|
# in PC/launcher.c must also be updated.
|
||||||
|
|
||||||
MAGIC_NUMBER = (3401).to_bytes(2, 'little') + b'\r\n'
|
MAGIC_NUMBER = (3410).to_bytes(2, 'little') + b'\r\n'
|
||||||
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
|
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
|
||||||
|
|
||||||
_PYCACHE = '__pycache__'
|
_PYCACHE = '__pycache__'
|
||||||
|
|
|
@ -272,6 +272,7 @@ def iscode(object):
|
||||||
| 16=nested | 32=generator | 64=nofree | 128=coroutine
|
| 16=nested | 32=generator | 64=nofree | 128=coroutine
|
||||||
| 256=iterable_coroutine | 512=async_generator
|
| 256=iterable_coroutine | 512=async_generator
|
||||||
co_freevars tuple of names of free variables
|
co_freevars tuple of names of free variables
|
||||||
|
co_posonlyargcount number of positional only arguments
|
||||||
co_kwonlyargcount number of keyword only arguments (not including ** arg)
|
co_kwonlyargcount number of keyword only arguments (not including ** arg)
|
||||||
co_lnotab encoded mapping of line numbers to bytecode indices
|
co_lnotab encoded mapping of line numbers to bytecode indices
|
||||||
co_name name with which this code object was defined
|
co_name name with which this code object was defined
|
||||||
|
@ -1031,26 +1032,20 @@ def getargs(co):
|
||||||
'args' is the list of argument names. Keyword-only arguments are
|
'args' is the list of argument names. Keyword-only arguments are
|
||||||
appended. 'varargs' and 'varkw' are the names of the * and **
|
appended. 'varargs' and 'varkw' are the names of the * and **
|
||||||
arguments or None."""
|
arguments or None."""
|
||||||
args, varargs, kwonlyargs, varkw = _getfullargs(co)
|
|
||||||
return Arguments(args + kwonlyargs, varargs, varkw)
|
|
||||||
|
|
||||||
def _getfullargs(co):
|
|
||||||
"""Get information about the arguments accepted by a code object.
|
|
||||||
|
|
||||||
Four things are returned: (args, varargs, kwonlyargs, varkw), where
|
|
||||||
'args' and 'kwonlyargs' are lists of argument names, and 'varargs'
|
|
||||||
and 'varkw' are the names of the * and ** arguments or None."""
|
|
||||||
|
|
||||||
if not iscode(co):
|
if not iscode(co):
|
||||||
raise TypeError('{!r} is not a code object'.format(co))
|
raise TypeError('{!r} is not a code object'.format(co))
|
||||||
|
|
||||||
nargs = co.co_argcount
|
|
||||||
names = co.co_varnames
|
names = co.co_varnames
|
||||||
|
nargs = co.co_argcount
|
||||||
|
nposonlyargs = co.co_posonlyargcount
|
||||||
nkwargs = co.co_kwonlyargcount
|
nkwargs = co.co_kwonlyargcount
|
||||||
args = list(names[:nargs])
|
nposargs = nargs + nposonlyargs
|
||||||
kwonlyargs = list(names[nargs:nargs+nkwargs])
|
posonlyargs = list(names[:nposonlyargs])
|
||||||
|
args = list(names[nposonlyargs:nposonlyargs+nargs])
|
||||||
|
kwonlyargs = list(names[nposargs:nposargs+nkwargs])
|
||||||
step = 0
|
step = 0
|
||||||
|
|
||||||
|
nargs += nposonlyargs
|
||||||
nargs += nkwargs
|
nargs += nkwargs
|
||||||
varargs = None
|
varargs = None
|
||||||
if co.co_flags & CO_VARARGS:
|
if co.co_flags & CO_VARARGS:
|
||||||
|
@ -1059,8 +1054,7 @@ def _getfullargs(co):
|
||||||
varkw = None
|
varkw = None
|
||||||
if co.co_flags & CO_VARKEYWORDS:
|
if co.co_flags & CO_VARKEYWORDS:
|
||||||
varkw = co.co_varnames[nargs]
|
varkw = co.co_varnames[nargs]
|
||||||
return args, varargs, kwonlyargs, varkw
|
return Arguments(posonlyargs + args + kwonlyargs, varargs, varkw)
|
||||||
|
|
||||||
|
|
||||||
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
|
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
|
||||||
|
|
||||||
|
@ -1087,15 +1081,16 @@ def getargspec(func):
|
||||||
warnings.warn("inspect.getargspec() is deprecated since Python 3.0, "
|
warnings.warn("inspect.getargspec() is deprecated since Python 3.0, "
|
||||||
"use inspect.signature() or inspect.getfullargspec()",
|
"use inspect.signature() or inspect.getfullargspec()",
|
||||||
DeprecationWarning, stacklevel=2)
|
DeprecationWarning, stacklevel=2)
|
||||||
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
|
args, varargs, varkw, defaults, posonlyargs, kwonlyargs, \
|
||||||
getfullargspec(func)
|
kwonlydefaults, ann = getfullargspec(func)
|
||||||
if kwonlyargs or ann:
|
if posonlyargs or kwonlyargs or ann:
|
||||||
raise ValueError("Function has keyword-only parameters or annotations"
|
raise ValueError("Function has positional-only, keyword-only parameters"
|
||||||
", use getfullargspec() API which can support them")
|
" or annotations, use getfullargspec() API which can"
|
||||||
|
" support them")
|
||||||
return ArgSpec(args, varargs, varkw, defaults)
|
return ArgSpec(args, varargs, varkw, defaults)
|
||||||
|
|
||||||
FullArgSpec = namedtuple('FullArgSpec',
|
FullArgSpec = namedtuple('FullArgSpec',
|
||||||
'args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations')
|
'args, varargs, varkw, defaults, posonlyargs, kwonlyargs, kwonlydefaults, annotations')
|
||||||
|
|
||||||
def getfullargspec(func):
|
def getfullargspec(func):
|
||||||
"""Get the names and default values of a callable object's parameters.
|
"""Get the names and default values of a callable object's parameters.
|
||||||
|
@ -1145,6 +1140,7 @@ def getfullargspec(func):
|
||||||
args = []
|
args = []
|
||||||
varargs = None
|
varargs = None
|
||||||
varkw = None
|
varkw = None
|
||||||
|
posonlyargs = []
|
||||||
kwonlyargs = []
|
kwonlyargs = []
|
||||||
defaults = ()
|
defaults = ()
|
||||||
annotations = {}
|
annotations = {}
|
||||||
|
@ -1159,7 +1155,9 @@ def getfullargspec(func):
|
||||||
name = param.name
|
name = param.name
|
||||||
|
|
||||||
if kind is _POSITIONAL_ONLY:
|
if kind is _POSITIONAL_ONLY:
|
||||||
args.append(name)
|
posonlyargs.append(name)
|
||||||
|
if param.default is not param.empty:
|
||||||
|
defaults += (param.default,)
|
||||||
elif kind is _POSITIONAL_OR_KEYWORD:
|
elif kind is _POSITIONAL_OR_KEYWORD:
|
||||||
args.append(name)
|
args.append(name)
|
||||||
if param.default is not param.empty:
|
if param.default is not param.empty:
|
||||||
|
@ -1185,7 +1183,7 @@ def getfullargspec(func):
|
||||||
defaults = None
|
defaults = None
|
||||||
|
|
||||||
return FullArgSpec(args, varargs, varkw, defaults,
|
return FullArgSpec(args, varargs, varkw, defaults,
|
||||||
kwonlyargs, kwdefaults, annotations)
|
posonlyargs, kwonlyargs, kwdefaults, annotations)
|
||||||
|
|
||||||
|
|
||||||
ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')
|
ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')
|
||||||
|
@ -1216,7 +1214,8 @@ def formatannotationrelativeto(object):
|
||||||
return _formatannotation
|
return _formatannotation
|
||||||
|
|
||||||
def formatargspec(args, varargs=None, varkw=None, defaults=None,
|
def formatargspec(args, varargs=None, varkw=None, defaults=None,
|
||||||
kwonlyargs=(), kwonlydefaults={}, annotations={},
|
posonlyargs=(), kwonlyargs=(), kwonlydefaults={},
|
||||||
|
annotations={},
|
||||||
formatarg=str,
|
formatarg=str,
|
||||||
formatvarargs=lambda name: '*' + name,
|
formatvarargs=lambda name: '*' + name,
|
||||||
formatvarkw=lambda name: '**' + name,
|
formatvarkw=lambda name: '**' + name,
|
||||||
|
@ -1249,12 +1248,17 @@ def formatargspec(args, varargs=None, varkw=None, defaults=None,
|
||||||
return result
|
return result
|
||||||
specs = []
|
specs = []
|
||||||
if defaults:
|
if defaults:
|
||||||
firstdefault = len(args) - len(defaults)
|
firstdefault = len(posonlyargs) + len(args) - len(defaults)
|
||||||
for i, arg in enumerate(args):
|
posonly_left = len(posonlyargs)
|
||||||
|
for i, arg in enumerate([*posonlyargs, *args]):
|
||||||
spec = formatargandannotation(arg)
|
spec = formatargandannotation(arg)
|
||||||
if defaults and i >= firstdefault:
|
if defaults and i >= firstdefault:
|
||||||
spec = spec + formatvalue(defaults[i - firstdefault])
|
spec = spec + formatvalue(defaults[i - firstdefault])
|
||||||
specs.append(spec)
|
specs.append(spec)
|
||||||
|
posonly_left -= 1
|
||||||
|
if posonlyargs and posonly_left == 0:
|
||||||
|
specs.append('/')
|
||||||
|
|
||||||
if varargs is not None:
|
if varargs is not None:
|
||||||
specs.append(formatvarargs(formatargandannotation(varargs)))
|
specs.append(formatvarargs(formatargandannotation(varargs)))
|
||||||
else:
|
else:
|
||||||
|
@ -1342,7 +1346,8 @@ def getcallargs(*func_and_positional, **named):
|
||||||
func = func_and_positional[0]
|
func = func_and_positional[0]
|
||||||
positional = func_and_positional[1:]
|
positional = func_and_positional[1:]
|
||||||
spec = getfullargspec(func)
|
spec = getfullargspec(func)
|
||||||
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = spec
|
(args, varargs, varkw, defaults, posonlyargs,
|
||||||
|
kwonlyargs, kwonlydefaults, ann) = spec
|
||||||
f_name = func.__name__
|
f_name = func.__name__
|
||||||
arg2value = {}
|
arg2value = {}
|
||||||
|
|
||||||
|
@ -1351,12 +1356,16 @@ def getcallargs(*func_and_positional, **named):
|
||||||
# implicit 'self' (or 'cls' for classmethods) argument
|
# implicit 'self' (or 'cls' for classmethods) argument
|
||||||
positional = (func.__self__,) + positional
|
positional = (func.__self__,) + positional
|
||||||
num_pos = len(positional)
|
num_pos = len(positional)
|
||||||
|
num_posonlyargs = len(posonlyargs)
|
||||||
num_args = len(args)
|
num_args = len(args)
|
||||||
num_defaults = len(defaults) if defaults else 0
|
num_defaults = len(defaults) if defaults else 0
|
||||||
|
|
||||||
|
n = min(num_pos, num_posonlyargs)
|
||||||
|
for i in range(num_posonlyargs):
|
||||||
|
arg2value[posonlyargs[i]] = positional[i]
|
||||||
n = min(num_pos, num_args)
|
n = min(num_pos, num_args)
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
arg2value[args[i]] = positional[i]
|
arg2value[args[i]] = positional[num_posonlyargs+i]
|
||||||
if varargs:
|
if varargs:
|
||||||
arg2value[varargs] = tuple(positional[n:])
|
arg2value[varargs] = tuple(positional[n:])
|
||||||
possible_kwargs = set(args + kwonlyargs)
|
possible_kwargs = set(args + kwonlyargs)
|
||||||
|
@ -2137,9 +2146,12 @@ def _signature_from_function(cls, func):
|
||||||
func_code = func.__code__
|
func_code = func.__code__
|
||||||
pos_count = func_code.co_argcount
|
pos_count = func_code.co_argcount
|
||||||
arg_names = func_code.co_varnames
|
arg_names = func_code.co_varnames
|
||||||
positional = tuple(arg_names[:pos_count])
|
posonly_count = func_code.co_posonlyargcount
|
||||||
|
positional_count = posonly_count + pos_count
|
||||||
|
positional_only = tuple(arg_names[:posonly_count])
|
||||||
|
positional = tuple(arg_names[posonly_count:positional_count])
|
||||||
keyword_only_count = func_code.co_kwonlyargcount
|
keyword_only_count = func_code.co_kwonlyargcount
|
||||||
keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)]
|
keyword_only = arg_names[positional_count:(positional_count + keyword_only_count)]
|
||||||
annotations = func.__annotations__
|
annotations = func.__annotations__
|
||||||
defaults = func.__defaults__
|
defaults = func.__defaults__
|
||||||
kwdefaults = func.__kwdefaults__
|
kwdefaults = func.__kwdefaults__
|
||||||
|
@ -2151,23 +2163,33 @@ def _signature_from_function(cls, func):
|
||||||
|
|
||||||
parameters = []
|
parameters = []
|
||||||
|
|
||||||
|
non_default_count = positional_count - pos_default_count
|
||||||
|
all_positional = positional_only + positional
|
||||||
|
|
||||||
|
posonly_left = posonly_count
|
||||||
|
|
||||||
# Non-keyword-only parameters w/o defaults.
|
# Non-keyword-only parameters w/o defaults.
|
||||||
non_default_count = pos_count - pos_default_count
|
for name in all_positional[:non_default_count]:
|
||||||
for name in positional[:non_default_count]:
|
kind = _POSITIONAL_ONLY if posonly_left else _POSITIONAL_OR_KEYWORD
|
||||||
annotation = annotations.get(name, _empty)
|
annotation = annotations.get(name, _empty)
|
||||||
parameters.append(Parameter(name, annotation=annotation,
|
parameters.append(Parameter(name, annotation=annotation,
|
||||||
kind=_POSITIONAL_OR_KEYWORD))
|
kind=kind))
|
||||||
|
if posonly_left:
|
||||||
|
posonly_left -= 1
|
||||||
|
|
||||||
# ... w/ defaults.
|
# ... w/ defaults.
|
||||||
for offset, name in enumerate(positional[non_default_count:]):
|
for offset, name in enumerate(all_positional[non_default_count:]):
|
||||||
|
kind = _POSITIONAL_ONLY if posonly_left else _POSITIONAL_OR_KEYWORD
|
||||||
annotation = annotations.get(name, _empty)
|
annotation = annotations.get(name, _empty)
|
||||||
parameters.append(Parameter(name, annotation=annotation,
|
parameters.append(Parameter(name, annotation=annotation,
|
||||||
kind=_POSITIONAL_OR_KEYWORD,
|
kind=kind,
|
||||||
default=defaults[offset]))
|
default=defaults[offset]))
|
||||||
|
if posonly_left:
|
||||||
|
posonly_left -= 1
|
||||||
|
|
||||||
# *args
|
# *args
|
||||||
if func_code.co_flags & CO_VARARGS:
|
if func_code.co_flags & CO_VARARGS:
|
||||||
name = arg_names[pos_count + keyword_only_count]
|
name = arg_names[positional_count + keyword_only_count]
|
||||||
annotation = annotations.get(name, _empty)
|
annotation = annotations.get(name, _empty)
|
||||||
parameters.append(Parameter(name, annotation=annotation,
|
parameters.append(Parameter(name, annotation=annotation,
|
||||||
kind=_VAR_POSITIONAL))
|
kind=_VAR_POSITIONAL))
|
||||||
|
@ -2184,7 +2206,7 @@ def _signature_from_function(cls, func):
|
||||||
default=default))
|
default=default))
|
||||||
# **kwargs
|
# **kwargs
|
||||||
if func_code.co_flags & CO_VARKEYWORDS:
|
if func_code.co_flags & CO_VARKEYWORDS:
|
||||||
index = pos_count + keyword_only_count
|
index = positional_count + keyword_only_count
|
||||||
if func_code.co_flags & CO_VARARGS:
|
if func_code.co_flags & CO_VARARGS:
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
|
|
|
@ -619,8 +619,9 @@ class ModuleFinder:
|
||||||
if isinstance(consts[i], type(co)):
|
if isinstance(consts[i], type(co)):
|
||||||
consts[i] = self.replace_paths_in_code(consts[i])
|
consts[i] = self.replace_paths_in_code(consts[i])
|
||||||
|
|
||||||
return types.CodeType(co.co_argcount, co.co_kwonlyargcount,
|
return types.CodeType(co.co_argcount, co.co_posonlyargcount,
|
||||||
co.co_nlocals, co.co_stacksize, co.co_flags,
|
co.co_kwonlyargcount, co.co_nlocals,
|
||||||
|
co.co_stacksize, co.co_flags,
|
||||||
co.co_code, tuple(consts), co.co_names,
|
co.co_code, tuple(consts), co.co_names,
|
||||||
co.co_varnames, new_filename, co.co_name,
|
co.co_varnames, new_filename, co.co_name,
|
||||||
co.co_firstlineno, co.co_lnotab, co.co_freevars,
|
co.co_firstlineno, co.co_lnotab, co.co_freevars,
|
||||||
|
|
|
@ -5,7 +5,7 @@ import sys, inspect
|
||||||
# line 5
|
# line 5
|
||||||
|
|
||||||
# line 7
|
# line 7
|
||||||
def spam(a, b, c, d=3, e=4, f=5, *g, **h):
|
def spam(a, /, b, c, d=3, e=4, f=5, *g, **h):
|
||||||
eggs(b + d, c + f)
|
eggs(b + d, c + f)
|
||||||
|
|
||||||
# line 11
|
# line 11
|
||||||
|
|
|
@ -137,3 +137,19 @@ class cls135:
|
||||||
def func137():
|
def func137():
|
||||||
never_reached1
|
never_reached1
|
||||||
never_reached2
|
never_reached2
|
||||||
|
|
||||||
|
#line 141
|
||||||
|
def positional_only_arg(a, /):
|
||||||
|
pass
|
||||||
|
|
||||||
|
#line 145
|
||||||
|
def all_markers(a, b, /, c, d, *, e, f):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# line 149
|
||||||
|
def all_markers_with_args_and_kwargs(a, b, /, c, d, *args, e, f, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
#line 153
|
||||||
|
def all_markers_with_defaults(a, b=1, /, c=2, d=3, *, e=4, f=5):
|
||||||
|
pass
|
||||||
|
|
|
@ -319,14 +319,14 @@ class AST_Tests(unittest.TestCase):
|
||||||
|
|
||||||
def test_arguments(self):
|
def test_arguments(self):
|
||||||
x = ast.arguments()
|
x = ast.arguments()
|
||||||
self.assertEqual(x._fields, ('args', 'vararg', 'kwonlyargs',
|
self.assertEqual(x._fields, ('args', 'posonlyargs', 'vararg', 'kwonlyargs',
|
||||||
'kw_defaults', 'kwarg', 'defaults'))
|
'kw_defaults', 'kwarg', 'defaults'))
|
||||||
|
|
||||||
with self.assertRaises(AttributeError):
|
with self.assertRaises(AttributeError):
|
||||||
x.vararg
|
x.vararg
|
||||||
|
|
||||||
x = ast.arguments(*range(1, 7))
|
x = ast.arguments(*range(1, 8))
|
||||||
self.assertEqual(x.vararg, 2)
|
self.assertEqual(x.vararg, 3)
|
||||||
|
|
||||||
def test_field_attr_writable(self):
|
def test_field_attr_writable(self):
|
||||||
x = ast.Num()
|
x = ast.Num()
|
||||||
|
@ -816,22 +816,25 @@ class ASTValidatorTests(unittest.TestCase):
|
||||||
self.mod(m, "must have Load context", "eval")
|
self.mod(m, "must have Load context", "eval")
|
||||||
|
|
||||||
def _check_arguments(self, fac, check):
|
def _check_arguments(self, fac, check):
|
||||||
def arguments(args=None, vararg=None,
|
def arguments(args=None, posonlyargs=None, vararg=None,
|
||||||
kwonlyargs=None, kwarg=None,
|
kwonlyargs=None, kwarg=None,
|
||||||
defaults=None, kw_defaults=None):
|
defaults=None, kw_defaults=None):
|
||||||
if args is None:
|
if args is None:
|
||||||
args = []
|
args = []
|
||||||
|
if posonlyargs is None:
|
||||||
|
posonlyargs = []
|
||||||
if kwonlyargs is None:
|
if kwonlyargs is None:
|
||||||
kwonlyargs = []
|
kwonlyargs = []
|
||||||
if defaults is None:
|
if defaults is None:
|
||||||
defaults = []
|
defaults = []
|
||||||
if kw_defaults is None:
|
if kw_defaults is None:
|
||||||
kw_defaults = []
|
kw_defaults = []
|
||||||
args = ast.arguments(args, vararg, kwonlyargs, kw_defaults,
|
args = ast.arguments(args, posonlyargs, vararg, kwonlyargs,
|
||||||
kwarg, defaults)
|
kw_defaults, kwarg, defaults)
|
||||||
return fac(args)
|
return fac(args)
|
||||||
args = [ast.arg("x", ast.Name("x", ast.Store()))]
|
args = [ast.arg("x", ast.Name("x", ast.Store()))]
|
||||||
check(arguments(args=args), "must have Load context")
|
check(arguments(args=args), "must have Load context")
|
||||||
|
check(arguments(posonlyargs=args), "must have Load context")
|
||||||
check(arguments(kwonlyargs=args), "must have Load context")
|
check(arguments(kwonlyargs=args), "must have Load context")
|
||||||
check(arguments(defaults=[ast.Num(3)]),
|
check(arguments(defaults=[ast.Num(3)]),
|
||||||
"more positional defaults than args")
|
"more positional defaults than args")
|
||||||
|
@ -847,7 +850,7 @@ class ASTValidatorTests(unittest.TestCase):
|
||||||
"must have Load context")
|
"must have Load context")
|
||||||
|
|
||||||
def test_funcdef(self):
|
def test_funcdef(self):
|
||||||
a = ast.arguments([], None, [], [], None, [])
|
a = ast.arguments([], [], None, [], [], None, [])
|
||||||
f = ast.FunctionDef("x", a, [], [], None)
|
f = ast.FunctionDef("x", a, [], [], None)
|
||||||
self.stmt(f, "empty body on FunctionDef")
|
self.stmt(f, "empty body on FunctionDef")
|
||||||
f = ast.FunctionDef("x", a, [ast.Pass()], [ast.Name("x", ast.Store())],
|
f = ast.FunctionDef("x", a, [ast.Pass()], [ast.Name("x", ast.Store())],
|
||||||
|
@ -1013,7 +1016,7 @@ class ASTValidatorTests(unittest.TestCase):
|
||||||
self.expr(u, "must have Load context")
|
self.expr(u, "must have Load context")
|
||||||
|
|
||||||
def test_lambda(self):
|
def test_lambda(self):
|
||||||
a = ast.arguments([], None, [], [], None, [])
|
a = ast.arguments([], [], None, [], [], None, [])
|
||||||
self.expr(ast.Lambda(a, ast.Name("x", ast.Store())),
|
self.expr(ast.Lambda(a, ast.Name("x", ast.Store())),
|
||||||
"must have Load context")
|
"must have Load context")
|
||||||
def fac(args):
|
def fac(args):
|
||||||
|
@ -1636,17 +1639,17 @@ def main():
|
||||||
exec_results = [
|
exec_results = [
|
||||||
('Module', [('Expr', (1, 0), ('Constant', (1, 0), None, None))], []),
|
('Module', [('Expr', (1, 0), ('Constant', (1, 0), None, None))], []),
|
||||||
('Module', [('Expr', (1, 0), ('Constant', (1, 0), 'module docstring', None))], []),
|
('Module', [('Expr', (1, 0), ('Constant', (1, 0), 'module docstring', None))], []),
|
||||||
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Pass', (1, 9))], [], None, None)], []),
|
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9))], [], None, None)], []),
|
||||||
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Expr', (1, 9), ('Constant', (1, 9), 'function docstring', None))], [], None, None)], []),
|
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9), ('Constant', (1, 9), 'function docstring', None))], [], None, None)], []),
|
||||||
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10))], [], None, None)], []),
|
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 10))], [], None, None)], []),
|
||||||
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], None, [], [], None, [('Constant', (1, 8), 0, None)]), [('Pass', (1, 12))], [], None, None)], []),
|
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8), 0, None)]), [('Pass', (1, 12))], [], None, None)], []),
|
||||||
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], ('arg', (1, 7), 'args', None, None), [], [], None, []), [('Pass', (1, 14))], [], None, None)], []),
|
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], ('arg', (1, 7), 'args', None, None), [], [], None, []), [('Pass', (1, 14))], [], None, None)], []),
|
||||||
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], ('arg', (1, 8), 'kwargs', None, None), []), [('Pass', (1, 17))], [], None, None)], []),
|
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], ('arg', (1, 8), 'kwargs', None, None), []), [('Pass', (1, 17))], [], None, None)], []),
|
||||||
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None), ('arg', (1, 9), 'b', None, None), ('arg', (1, 14), 'c', None, None), ('arg', (1, 22), 'd', None, None), ('arg', (1, 28), 'e', None, None)], ('arg', (1, 35), 'args', None, None), [('arg', (1, 41), 'f', None, None)], [('Constant', (1, 43), 42, None)], ('arg', (1, 49), 'kwargs', None, None), [('Constant', (1, 11), 1, None), ('Constant', (1, 16), None, None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Expr', (1, 58), ('Constant', (1, 58), 'doc for f()', None))], [], None, None)], []),
|
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None), ('arg', (1, 9), 'b', None, None), ('arg', (1, 14), 'c', None, None), ('arg', (1, 22), 'd', None, None), ('arg', (1, 28), 'e', None, None)], [], ('arg', (1, 35), 'args', None, None), [('arg', (1, 41), 'f', None, None)], [('Constant', (1, 43), 42, None)], ('arg', (1, 49), 'kwargs', None, None), [('Constant', (1, 11), 1, None), ('Constant', (1, 16), None, None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Expr', (1, 58), ('Constant', (1, 58), 'doc for f()', None))], [], None, None)], []),
|
||||||
('Module', [('ClassDef', (1, 0), 'C', [], [], [('Pass', (1, 8))], [])], []),
|
('Module', [('ClassDef', (1, 0), 'C', [], [], [('Pass', (1, 8))], [])], []),
|
||||||
('Module', [('ClassDef', (1, 0), 'C', [], [], [('Expr', (1, 9), ('Constant', (1, 9), 'docstring for class C', None))], [])], []),
|
('Module', [('ClassDef', (1, 0), 'C', [], [], [('Expr', (1, 9), ('Constant', (1, 9), 'docstring for class C', None))], [])], []),
|
||||||
('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], [('Pass', (1, 17))], [])], []),
|
('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], [('Pass', (1, 17))], [])], []),
|
||||||
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Return', (1, 8), ('Constant', (1, 15), 1, None))], [], None, None)], []),
|
('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8), ('Constant', (1, 15), 1, None))], [], None, None)], []),
|
||||||
('Module', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])], []),
|
('Module', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])], []),
|
||||||
('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Constant', (1, 4), 1, None), None)], []),
|
('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Constant', (1, 4), 1, None), None)], []),
|
||||||
('Module', [('Assign', (1, 0), [('Tuple', (1, 0), [('Name', (1, 0), 'a', ('Store',)), ('Name', (1, 2), 'b', ('Store',))], ('Store',))], ('Name', (1, 6), 'c', ('Load',)), None)], []),
|
('Module', [('Assign', (1, 0), [('Tuple', (1, 0), [('Name', (1, 0), 'a', ('Store',)), ('Name', (1, 2), 'b', ('Store',))], ('Store',))], ('Name', (1, 6), 'c', ('Load',)), None)], []),
|
||||||
|
@ -1677,16 +1680,16 @@ exec_results = [
|
||||||
('Module', [('Expr', (1, 0), ('DictComp', (1, 0), ('Name', (1, 1), 'a', ('Load',)), ('Name', (1, 5), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'v', ('Store',)), ('Name', (1, 13), 'w', ('Store',))], ('Store',)), ('Name', (1, 18), 'x', ('Load',)), [], 0)]))], []),
|
('Module', [('Expr', (1, 0), ('DictComp', (1, 0), ('Name', (1, 1), 'a', ('Load',)), ('Name', (1, 5), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'v', ('Store',)), ('Name', (1, 13), 'w', ('Store',))], ('Store',)), ('Name', (1, 18), 'x', ('Load',)), [], 0)]))], []),
|
||||||
('Module', [('Expr', (1, 0), ('SetComp', (1, 0), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 12), 'x', ('Load',)), [('Name', (1, 17), 'g', ('Load',))], 0)]))], []),
|
('Module', [('Expr', (1, 0), ('SetComp', (1, 0), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 12), 'x', ('Load',)), [('Name', (1, 17), 'g', ('Load',))], 0)]))], []),
|
||||||
('Module', [('Expr', (1, 0), ('SetComp', (1, 0), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7), [('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 9), 'm', ('Store',))], ('Store',)), ('Name', (1, 14), 'x', ('Load',)), [], 0)]))], []),
|
('Module', [('Expr', (1, 0), ('SetComp', (1, 0), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7), [('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 9), 'm', ('Store',))], ('Store',)), ('Name', (1, 14), 'x', ('Load',)), [], 0)]))], []),
|
||||||
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Expr', (2, 1), ('Constant', (2, 1), 'async function', None)), ('Expr', (3, 1), ('Await', (3, 1), ('Call', (3, 7), ('Name', (3, 7), 'something', ('Load',)), [], [])))], [], None, None)], []),
|
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1), ('Constant', (2, 1), 'async function', None)), ('Expr', (3, 1), ('Await', (3, 1), ('Call', (3, 7), ('Name', (3, 7), 'something', ('Load',)), [], [])))], [], None, None)], []),
|
||||||
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('AsyncFor', (2, 1), ('Name', (2, 11), 'e', ('Store',)), ('Name', (2, 16), 'i', ('Load',)), [('Expr', (2, 19), ('Constant', (2, 19), 1, None))], [('Expr', (3, 7), ('Constant', (3, 7), 2, None))], None)], [], None, None)], []),
|
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1), ('Name', (2, 11), 'e', ('Store',)), ('Name', (2, 16), 'i', ('Load',)), [('Expr', (2, 19), ('Constant', (2, 19), 1, None))], [('Expr', (3, 7), ('Constant', (3, 7), 2, None))], None)], [], None, None)], []),
|
||||||
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('AsyncWith', (2, 1), [('withitem', ('Name', (2, 12), 'a', ('Load',)), ('Name', (2, 17), 'b', ('Store',)))], [('Expr', (2, 20), ('Constant', (2, 20), 1, None))], None)], [], None, None)], []),
|
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1), [('withitem', ('Name', (2, 12), 'a', ('Load',)), ('Name', (2, 17), 'b', ('Store',)))], [('Expr', (2, 20), ('Constant', (2, 20), 1, None))], None)], [], None, None)], []),
|
||||||
('Module', [('Expr', (1, 0), ('Dict', (1, 0), [None, ('Constant', (1, 10), 2, None)], [('Dict', (1, 3), [('Constant', (1, 4), 1, None)], [('Constant', (1, 6), 2, None)]), ('Constant', (1, 12), 3, None)]))], []),
|
('Module', [('Expr', (1, 0), ('Dict', (1, 0), [None, ('Constant', (1, 10), 2, None)], [('Dict', (1, 3), [('Constant', (1, 4), 1, None)], [('Constant', (1, 6), 2, None)]), ('Constant', (1, 12), 3, None)]))], []),
|
||||||
('Module', [('Expr', (1, 0), ('Set', (1, 0), [('Starred', (1, 1), ('Set', (1, 2), [('Constant', (1, 3), 1, None), ('Constant', (1, 6), 2, None)]), ('Load',)), ('Constant', (1, 10), 3, None)]))], []),
|
('Module', [('Expr', (1, 0), ('Set', (1, 0), [('Starred', (1, 1), ('Set', (1, 2), [('Constant', (1, 3), 1, None), ('Constant', (1, 6), 2, None)]), ('Load',)), ('Constant', (1, 10), 3, None)]))], []),
|
||||||
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], None, [], [], None, []), [('Expr', (2, 1), ('ListComp', (2, 1), ('Name', (2, 2), 'i', ('Load',)), [('comprehension', ('Name', (2, 14), 'b', ('Store',)), ('Name', (2, 19), 'c', ('Load',)), [], 1)]))], [], None, None)], []),
|
('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1), ('ListComp', (2, 1), ('Name', (2, 2), 'i', ('Load',)), [('comprehension', ('Name', (2, 14), 'b', ('Store',)), ('Name', (2, 19), 'c', ('Load',)), [], 1)]))], [], None, None)], []),
|
||||||
('Module', [('FunctionDef', (3, 0), 'f', ('arguments', [], None, [], [], None, []), [('Pass', (3, 9))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])], None, None)], []),
|
('Module', [('FunctionDef', (3, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (3, 9))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])], None, None)], []),
|
||||||
('Module', [('AsyncFunctionDef', (3, 0), 'f', ('arguments', [], None, [], [], None, []), [('Pass', (3, 15))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])], None, None)], []),
|
('Module', [('AsyncFunctionDef', (3, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (3, 15))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])], None, None)], []),
|
||||||
('Module', [('ClassDef', (3, 0), 'C', [], [], [('Pass', (3, 9))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])])], []),
|
('Module', [('ClassDef', (3, 0), 'C', [], [], [('Pass', (3, 9))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 0), ('Name', (2, 1), 'deco2', ('Load',)), [], [])])], []),
|
||||||
('Module', [('FunctionDef', (2, 0), 'f', ('arguments', [], None, [], [], None, []), [('Pass', (2, 9))], [('Call', (1, 1), ('Name', (1, 1), 'deco', ('Load',)), [('GeneratorExp', (1, 5), ('Name', (1, 6), 'a', ('Load',)), [('comprehension', ('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 17), 'b', ('Load',)), [], 0)])], [])], None, None)], []),
|
('Module', [('FunctionDef', (2, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9))], [('Call', (1, 1), ('Name', (1, 1), 'deco', ('Load',)), [('GeneratorExp', (1, 5), ('Name', (1, 6), 'a', ('Load',)), [('comprehension', ('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 17), 'b', ('Load',)), [], 0)])], [])], None, None)], []),
|
||||||
('Module', [('Expr', (1, 0), ('NamedExpr', (1, 1), ('Name', (1, 1), 'a', ('Store',)), ('Constant', (1, 6), 1, None)))], []),
|
('Module', [('Expr', (1, 0), ('NamedExpr', (1, 1), ('Name', (1, 1), 'a', ('Store',)), ('Constant', (1, 6), 1, None)))], []),
|
||||||
]
|
]
|
||||||
single_results = [
|
single_results = [
|
||||||
|
@ -1697,7 +1700,7 @@ eval_results = [
|
||||||
('Expression', ('BoolOp', (1, 0), ('And',), [('Name', (1, 0), 'a', ('Load',)), ('Name', (1, 6), 'b', ('Load',))])),
|
('Expression', ('BoolOp', (1, 0), ('And',), [('Name', (1, 0), 'a', ('Load',)), ('Name', (1, 6), 'b', ('Load',))])),
|
||||||
('Expression', ('BinOp', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Add',), ('Name', (1, 4), 'b', ('Load',)))),
|
('Expression', ('BinOp', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Add',), ('Name', (1, 4), 'b', ('Load',)))),
|
||||||
('Expression', ('UnaryOp', (1, 0), ('Not',), ('Name', (1, 4), 'v', ('Load',)))),
|
('Expression', ('UnaryOp', (1, 0), ('Not',), ('Name', (1, 4), 'v', ('Load',)))),
|
||||||
('Expression', ('Lambda', (1, 0), ('arguments', [], None, [], [], None, []), ('Constant', (1, 7), None, None))),
|
('Expression', ('Lambda', (1, 0), ('arguments', [], [], None, [], [], None, []), ('Constant', (1, 7), None, None))),
|
||||||
('Expression', ('Dict', (1, 0), [('Constant', (1, 2), 1, None)], [('Constant', (1, 4), 2, None)])),
|
('Expression', ('Dict', (1, 0), [('Constant', (1, 2), 1, None)], [('Constant', (1, 4), 2, None)])),
|
||||||
('Expression', ('Dict', (1, 0), [], [])),
|
('Expression', ('Dict', (1, 0), [], [])),
|
||||||
('Expression', ('Set', (1, 0), [('Constant', (1, 1), None, None)])),
|
('Expression', ('Set', (1, 0), [('Constant', (1, 1), None, None)])),
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
>>> dump(f.__code__)
|
>>> dump(f.__code__)
|
||||||
name: f
|
name: f
|
||||||
argcount: 1
|
argcount: 1
|
||||||
|
posonlyargcount: 0
|
||||||
kwonlyargcount: 0
|
kwonlyargcount: 0
|
||||||
names: ()
|
names: ()
|
||||||
varnames: ('x', 'g')
|
varnames: ('x', 'g')
|
||||||
|
@ -21,6 +22,7 @@ consts: ('None', '<code object g>', "'f.<locals>.g'")
|
||||||
>>> dump(f(4).__code__)
|
>>> dump(f(4).__code__)
|
||||||
name: g
|
name: g
|
||||||
argcount: 1
|
argcount: 1
|
||||||
|
posonlyargcount: 0
|
||||||
kwonlyargcount: 0
|
kwonlyargcount: 0
|
||||||
names: ()
|
names: ()
|
||||||
varnames: ('y',)
|
varnames: ('y',)
|
||||||
|
@ -40,6 +42,7 @@ consts: ('None',)
|
||||||
>>> dump(h.__code__)
|
>>> dump(h.__code__)
|
||||||
name: h
|
name: h
|
||||||
argcount: 2
|
argcount: 2
|
||||||
|
posonlyargcount: 0
|
||||||
kwonlyargcount: 0
|
kwonlyargcount: 0
|
||||||
names: ()
|
names: ()
|
||||||
varnames: ('x', 'y', 'a', 'b', 'c')
|
varnames: ('x', 'y', 'a', 'b', 'c')
|
||||||
|
@ -57,6 +60,7 @@ consts: ('None',)
|
||||||
>>> dump(attrs.__code__)
|
>>> dump(attrs.__code__)
|
||||||
name: attrs
|
name: attrs
|
||||||
argcount: 1
|
argcount: 1
|
||||||
|
posonlyargcount: 0
|
||||||
kwonlyargcount: 0
|
kwonlyargcount: 0
|
||||||
names: ('print', 'attr1', 'attr2', 'attr3')
|
names: ('print', 'attr1', 'attr2', 'attr3')
|
||||||
varnames: ('obj',)
|
varnames: ('obj',)
|
||||||
|
@ -75,6 +79,7 @@ consts: ('None',)
|
||||||
>>> dump(optimize_away.__code__)
|
>>> dump(optimize_away.__code__)
|
||||||
name: optimize_away
|
name: optimize_away
|
||||||
argcount: 0
|
argcount: 0
|
||||||
|
posonlyargcount: 0
|
||||||
kwonlyargcount: 0
|
kwonlyargcount: 0
|
||||||
names: ()
|
names: ()
|
||||||
varnames: ()
|
varnames: ()
|
||||||
|
@ -91,6 +96,7 @@ consts: ("'doc string'", 'None')
|
||||||
>>> dump(keywordonly_args.__code__)
|
>>> dump(keywordonly_args.__code__)
|
||||||
name: keywordonly_args
|
name: keywordonly_args
|
||||||
argcount: 2
|
argcount: 2
|
||||||
|
posonlyargcount: 0
|
||||||
kwonlyargcount: 1
|
kwonlyargcount: 1
|
||||||
names: ()
|
names: ()
|
||||||
varnames: ('a', 'b', 'k1')
|
varnames: ('a', 'b', 'k1')
|
||||||
|
@ -100,6 +106,23 @@ nlocals: 3
|
||||||
flags: 67
|
flags: 67
|
||||||
consts: ('None',)
|
consts: ('None',)
|
||||||
|
|
||||||
|
>>> def posonly_args(a,b,/,c):
|
||||||
|
... return a,b,c
|
||||||
|
...
|
||||||
|
|
||||||
|
>>> dump(posonly_args.__code__)
|
||||||
|
name: posonly_args
|
||||||
|
argcount: 1
|
||||||
|
posonlyargcount: 2
|
||||||
|
kwonlyargcount: 0
|
||||||
|
names: ()
|
||||||
|
varnames: ('a', 'b', 'c')
|
||||||
|
cellvars: ()
|
||||||
|
freevars: ()
|
||||||
|
nlocals: 3
|
||||||
|
flags: 67
|
||||||
|
consts: ('None',)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
|
@ -126,7 +149,8 @@ def consts(t):
|
||||||
|
|
||||||
def dump(co):
|
def dump(co):
|
||||||
"""Print out a text representation of a code object."""
|
"""Print out a text representation of a code object."""
|
||||||
for attr in ["name", "argcount", "kwonlyargcount", "names", "varnames",
|
for attr in ["name", "argcount", "posonlyargcount",
|
||||||
|
"kwonlyargcount", "names", "varnames",
|
||||||
"cellvars", "freevars", "nlocals", "flags"]:
|
"cellvars", "freevars", "nlocals", "flags"]:
|
||||||
print("%s: %s" % (attr, getattr(co, "co_" + attr)))
|
print("%s: %s" % (attr, getattr(co, "co_" + attr)))
|
||||||
print("consts:", tuple(consts(co.co_consts)))
|
print("consts:", tuple(consts(co.co_consts)))
|
||||||
|
@ -157,7 +181,7 @@ class CodeTest(unittest.TestCase):
|
||||||
def new_code(c):
|
def new_code(c):
|
||||||
'''A new code object with a __class__ cell added to freevars'''
|
'''A new code object with a __class__ cell added to freevars'''
|
||||||
return CodeType(
|
return CodeType(
|
||||||
c.co_argcount, c.co_kwonlyargcount, c.co_nlocals,
|
c.co_argcount, c.co_posonlyargcount, c.co_kwonlyargcount, c.co_nlocals,
|
||||||
c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names,
|
c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names,
|
||||||
c.co_varnames, c.co_filename, c.co_name, c.co_firstlineno,
|
c.co_varnames, c.co_filename, c.co_name, c.co_firstlineno,
|
||||||
c.co_lnotab, c.co_freevars + ('__class__',), c.co_cellvars)
|
c.co_lnotab, c.co_freevars + ('__class__',), c.co_cellvars)
|
||||||
|
|
|
@ -617,6 +617,7 @@ code_info_code_info = """\
|
||||||
Name: code_info
|
Name: code_info
|
||||||
Filename: (.*)
|
Filename: (.*)
|
||||||
Argument count: 1
|
Argument count: 1
|
||||||
|
Positional-only arguments: 0
|
||||||
Kw-only arguments: 0
|
Kw-only arguments: 0
|
||||||
Number of locals: 1
|
Number of locals: 1
|
||||||
Stack size: 3
|
Stack size: 3
|
||||||
|
@ -631,50 +632,53 @@ Variable names:
|
||||||
if sys.flags.optimize < 2 else (None,))
|
if sys.flags.optimize < 2 else (None,))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def tricky(x, y, z=True, *args, c, d, e=[], **kwds):
|
def tricky(a, b, /, x, y, z=True, *args, c, d, e=[], **kwds):
|
||||||
def f(c=c):
|
def f(c=c):
|
||||||
print(x, y, z, c, d, e, f)
|
print(a, b, x, y, z, c, d, e, f)
|
||||||
yield x, y, z, c, d, e, f
|
yield a, b, x, y, z, c, d, e, f
|
||||||
|
|
||||||
code_info_tricky = """\
|
code_info_tricky = """\
|
||||||
Name: tricky
|
Name: tricky
|
||||||
Filename: (.*)
|
Filename: (.*)
|
||||||
Argument count: 3
|
Argument count: 3
|
||||||
|
Positional-only arguments: 2
|
||||||
Kw-only arguments: 3
|
Kw-only arguments: 3
|
||||||
Number of locals: 8
|
Number of locals: 10
|
||||||
Stack size: 7
|
Stack size: 9
|
||||||
Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
|
Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
|
||||||
Constants:
|
Constants:
|
||||||
0: None
|
0: None
|
||||||
1: <code object f at (.*), file "(.*)", line (.*)>
|
1: <code object f at (.*), file "(.*)", line (.*)>
|
||||||
2: 'tricky.<locals>.f'
|
2: 'tricky.<locals>.f'
|
||||||
Variable names:
|
Variable names:
|
||||||
0: x
|
0: a
|
||||||
1: y
|
1: b
|
||||||
2: z
|
2: x
|
||||||
3: c
|
3: y
|
||||||
4: d
|
4: z
|
||||||
5: e
|
5: c
|
||||||
6: args
|
6: d
|
||||||
7: kwds
|
7: e
|
||||||
|
8: args
|
||||||
|
9: kwds
|
||||||
Cell variables:
|
Cell variables:
|
||||||
0: [edfxyz]
|
0: [abedfxyz]
|
||||||
1: [edfxyz]
|
1: [abedfxyz]
|
||||||
2: [edfxyz]
|
2: [abedfxyz]
|
||||||
3: [edfxyz]
|
3: [abedfxyz]
|
||||||
4: [edfxyz]
|
4: [abedfxyz]
|
||||||
5: [edfxyz]"""
|
5: [abedfxyz]"""
|
||||||
# NOTE: the order of the cell variables above depends on dictionary order!
|
# NOTE: the order of the cell variables above depends on dictionary order!
|
||||||
|
|
||||||
co_tricky_nested_f = tricky.__func__.__code__.co_consts[1]
|
co_tricky_nested_f = tricky.__func__.__code__.co_consts[1]
|
||||||
|
|
||||||
code_info_tricky_nested_f = """\
|
code_info_tricky_nested_f = """\
|
||||||
Name: f
|
|
||||||
Filename: (.*)
|
Filename: (.*)
|
||||||
Argument count: 1
|
Argument count: 1
|
||||||
|
Positional-only arguments: 0
|
||||||
Kw-only arguments: 0
|
Kw-only arguments: 0
|
||||||
Number of locals: 1
|
Number of locals: 1
|
||||||
Stack size: 8
|
Stack size: 10
|
||||||
Flags: OPTIMIZED, NEWLOCALS, NESTED
|
Flags: OPTIMIZED, NEWLOCALS, NESTED
|
||||||
Constants:
|
Constants:
|
||||||
0: None
|
0: None
|
||||||
|
@ -683,17 +687,18 @@ Names:
|
||||||
Variable names:
|
Variable names:
|
||||||
0: c
|
0: c
|
||||||
Free variables:
|
Free variables:
|
||||||
0: [edfxyz]
|
0: [abedfxyz]
|
||||||
1: [edfxyz]
|
1: [abedfxyz]
|
||||||
2: [edfxyz]
|
2: [abedfxyz]
|
||||||
3: [edfxyz]
|
3: [abedfxyz]
|
||||||
4: [edfxyz]
|
4: [abedfxyz]
|
||||||
5: [edfxyz]"""
|
5: [abedfxyz]"""
|
||||||
|
|
||||||
code_info_expr_str = """\
|
code_info_expr_str = """\
|
||||||
Name: <module>
|
Name: <module>
|
||||||
Filename: <disassembly>
|
Filename: <disassembly>
|
||||||
Argument count: 0
|
Argument count: 0
|
||||||
|
Positional-only arguments: 0
|
||||||
Kw-only arguments: 0
|
Kw-only arguments: 0
|
||||||
Number of locals: 0
|
Number of locals: 0
|
||||||
Stack size: 2
|
Stack size: 2
|
||||||
|
@ -707,6 +712,7 @@ code_info_simple_stmt_str = """\
|
||||||
Name: <module>
|
Name: <module>
|
||||||
Filename: <disassembly>
|
Filename: <disassembly>
|
||||||
Argument count: 0
|
Argument count: 0
|
||||||
|
Positional-only arguments: 0
|
||||||
Kw-only arguments: 0
|
Kw-only arguments: 0
|
||||||
Number of locals: 0
|
Number of locals: 0
|
||||||
Stack size: 2
|
Stack size: 2
|
||||||
|
@ -721,6 +727,7 @@ code_info_compound_stmt_str = """\
|
||||||
Name: <module>
|
Name: <module>
|
||||||
Filename: <disassembly>
|
Filename: <disassembly>
|
||||||
Argument count: 0
|
Argument count: 0
|
||||||
|
Positional-only arguments: 0
|
||||||
Kw-only arguments: 0
|
Kw-only arguments: 0
|
||||||
Number of locals: 0
|
Number of locals: 0
|
||||||
Stack size: 2
|
Stack size: 2
|
||||||
|
@ -742,6 +749,7 @@ code_info_async_def = """\
|
||||||
Name: async_def
|
Name: async_def
|
||||||
Filename: (.*)
|
Filename: (.*)
|
||||||
Argument count: 0
|
Argument count: 0
|
||||||
|
Positional-only arguments: 0
|
||||||
Kw-only arguments: 0
|
Kw-only arguments: 0
|
||||||
Number of locals: 2
|
Number of locals: 2
|
||||||
Stack size: 10
|
Stack size: 10
|
||||||
|
|
|
@ -581,6 +581,13 @@ class TestPartialMethod(unittest.TestCase):
|
||||||
for func in [self.A.static, self.A.cls, self.A.over_partial, self.A.nested, self.A.both]:
|
for func in [self.A.static, self.A.cls, self.A.over_partial, self.A.nested, self.A.both]:
|
||||||
self.assertFalse(getattr(func, '__isabstractmethod__', False))
|
self.assertFalse(getattr(func, '__isabstractmethod__', False))
|
||||||
|
|
||||||
|
def test_positional_only(self):
|
||||||
|
def f(a, b, /):
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
p = functools.partial(f, 1)
|
||||||
|
self.assertEqual(p(2), f(1, 2))
|
||||||
|
|
||||||
|
|
||||||
class TestUpdateWrapper(unittest.TestCase):
|
class TestUpdateWrapper(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -674,7 +674,8 @@ func_filename = func.__code__.co_filename
|
||||||
foreign_code = importlib.import_module.__code__
|
foreign_code = importlib.import_module.__code__
|
||||||
pos = constants.index(1)
|
pos = constants.index(1)
|
||||||
constants[pos] = foreign_code
|
constants[pos] = foreign_code
|
||||||
code = type(code)(code.co_argcount, code.co_kwonlyargcount,
|
code = type(code)(code.co_argcount, code.co_posonlyargcount,
|
||||||
|
code.co_kwonlyargcount,
|
||||||
code.co_nlocals, code.co_stacksize,
|
code.co_nlocals, code.co_stacksize,
|
||||||
code.co_flags, code.co_code, tuple(constants),
|
code.co_flags, code.co_code, tuple(constants),
|
||||||
code.co_names, code.co_varnames, code.co_filename,
|
code.co_names, code.co_varnames, code.co_filename,
|
||||||
|
|
|
@ -862,7 +862,7 @@ class MagicNumberTests(unittest.TestCase):
|
||||||
in advance. Such exceptional releases will then require an
|
in advance. Such exceptional releases will then require an
|
||||||
adjustment to this test case.
|
adjustment to this test case.
|
||||||
"""
|
"""
|
||||||
EXPECTED_MAGIC_NUMBER = 3400
|
EXPECTED_MAGIC_NUMBER = 3410
|
||||||
actual = int.from_bytes(importlib.util.MAGIC_NUMBER[:2], 'little')
|
actual = int.from_bytes(importlib.util.MAGIC_NUMBER[:2], 'little')
|
||||||
|
|
||||||
msg = (
|
msg = (
|
||||||
|
|
|
@ -763,30 +763,31 @@ class TestClassesAndFunctions(unittest.TestCase):
|
||||||
|
|
||||||
def assertFullArgSpecEquals(self, routine, args_e, varargs_e=None,
|
def assertFullArgSpecEquals(self, routine, args_e, varargs_e=None,
|
||||||
varkw_e=None, defaults_e=None,
|
varkw_e=None, defaults_e=None,
|
||||||
kwonlyargs_e=[], kwonlydefaults_e=None,
|
posonlyargs_e=[], kwonlyargs_e=[],
|
||||||
|
kwonlydefaults_e=None,
|
||||||
ann_e={}, formatted=None):
|
ann_e={}, formatted=None):
|
||||||
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
|
args, varargs, varkw, defaults, posonlyargs, kwonlyargs, kwonlydefaults, ann = \
|
||||||
inspect.getfullargspec(routine)
|
inspect.getfullargspec(routine)
|
||||||
self.assertEqual(args, args_e)
|
self.assertEqual(args, args_e)
|
||||||
self.assertEqual(varargs, varargs_e)
|
self.assertEqual(varargs, varargs_e)
|
||||||
self.assertEqual(varkw, varkw_e)
|
self.assertEqual(varkw, varkw_e)
|
||||||
self.assertEqual(defaults, defaults_e)
|
self.assertEqual(defaults, defaults_e)
|
||||||
|
self.assertEqual(posonlyargs, posonlyargs_e)
|
||||||
self.assertEqual(kwonlyargs, kwonlyargs_e)
|
self.assertEqual(kwonlyargs, kwonlyargs_e)
|
||||||
self.assertEqual(kwonlydefaults, kwonlydefaults_e)
|
self.assertEqual(kwonlydefaults, kwonlydefaults_e)
|
||||||
self.assertEqual(ann, ann_e)
|
self.assertEqual(ann, ann_e)
|
||||||
if formatted is not None:
|
if formatted is not None:
|
||||||
with self.assertWarns(DeprecationWarning):
|
with self.assertWarns(DeprecationWarning):
|
||||||
self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults,
|
self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults,
|
||||||
kwonlyargs, kwonlydefaults, ann),
|
posonlyargs, kwonlyargs,
|
||||||
|
kwonlydefaults, ann),
|
||||||
formatted)
|
formatted)
|
||||||
|
|
||||||
def test_getargspec(self):
|
def test_getargspec(self):
|
||||||
self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted='(x, y)')
|
self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted='(x, y)')
|
||||||
|
|
||||||
self.assertArgSpecEquals(mod.spam,
|
self.assertRaises(ValueError, self.assertArgSpecEquals,
|
||||||
['a', 'b', 'c', 'd', 'e', 'f'],
|
mod.spam, [])
|
||||||
'g', 'h', (3, 4, 5),
|
|
||||||
'(a, b, c, d=3, e=4, f=5, *g, **h)')
|
|
||||||
|
|
||||||
self.assertRaises(ValueError, self.assertArgSpecEquals,
|
self.assertRaises(ValueError, self.assertArgSpecEquals,
|
||||||
mod2.keyworded, [])
|
mod2.keyworded, [])
|
||||||
|
@ -810,6 +811,26 @@ class TestClassesAndFunctions(unittest.TestCase):
|
||||||
kwonlyargs_e=['arg'],
|
kwonlyargs_e=['arg'],
|
||||||
formatted='(*, arg)')
|
formatted='(*, arg)')
|
||||||
|
|
||||||
|
self.assertFullArgSpecEquals(mod2.all_markers, ['c', 'd'],
|
||||||
|
posonlyargs_e=['a', 'b'],
|
||||||
|
kwonlyargs_e=['e', 'f'],
|
||||||
|
formatted='(a, b, /, c, d, *, e, f)')
|
||||||
|
|
||||||
|
self.assertFullArgSpecEquals(mod2.all_markers_with_args_and_kwargs,
|
||||||
|
['c', 'd'],
|
||||||
|
posonlyargs_e=['a', 'b'],
|
||||||
|
varargs_e='args',
|
||||||
|
varkw_e='kwargs',
|
||||||
|
kwonlyargs_e=['e', 'f'],
|
||||||
|
formatted='(a, b, /, c, d, *args, e, f, **kwargs)')
|
||||||
|
|
||||||
|
self.assertFullArgSpecEquals(mod2.all_markers_with_defaults, ['c', 'd'],
|
||||||
|
defaults_e=(1,2,3),
|
||||||
|
posonlyargs_e=['a', 'b'],
|
||||||
|
kwonlyargs_e=['e', 'f'],
|
||||||
|
kwonlydefaults_e={'e': 4, 'f': 5},
|
||||||
|
formatted='(a, b=1, /, c=2, d=3, *, e=4, f=5)')
|
||||||
|
|
||||||
def test_argspec_api_ignores_wrapped(self):
|
def test_argspec_api_ignores_wrapped(self):
|
||||||
# Issue 20684: low level introspection API must ignore __wrapped__
|
# Issue 20684: low level introspection API must ignore __wrapped__
|
||||||
@functools.wraps(mod.spam)
|
@functools.wraps(mod.spam)
|
||||||
|
@ -856,7 +877,7 @@ class TestClassesAndFunctions(unittest.TestCase):
|
||||||
spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY)
|
spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY)
|
||||||
test.__signature__ = inspect.Signature(parameters=(spam_param,))
|
test.__signature__ = inspect.Signature(parameters=(spam_param,))
|
||||||
|
|
||||||
self.assertFullArgSpecEquals(test, args_e=['spam'], formatted='(spam)')
|
self.assertFullArgSpecEquals(test, [], posonlyargs_e=['spam'], formatted='(spam, /)')
|
||||||
|
|
||||||
def test_getfullargspec_signature_annos(self):
|
def test_getfullargspec_signature_annos(self):
|
||||||
def test(a:'spam') -> 'ham': pass
|
def test(a:'spam') -> 'ham': pass
|
||||||
|
@ -870,11 +891,11 @@ class TestClassesAndFunctions(unittest.TestCase):
|
||||||
@unittest.skipIf(MISSING_C_DOCSTRINGS,
|
@unittest.skipIf(MISSING_C_DOCSTRINGS,
|
||||||
"Signature information for builtins requires docstrings")
|
"Signature information for builtins requires docstrings")
|
||||||
def test_getfullargspec_builtin_methods(self):
|
def test_getfullargspec_builtin_methods(self):
|
||||||
self.assertFullArgSpecEquals(_pickle.Pickler.dump,
|
self.assertFullArgSpecEquals(_pickle.Pickler.dump, [],
|
||||||
args_e=['self', 'obj'], formatted='(self, obj)')
|
posonlyargs_e=['self', 'obj'], formatted='(self, obj, /)')
|
||||||
|
|
||||||
self.assertFullArgSpecEquals(_pickle.Pickler(io.BytesIO()).dump,
|
self.assertFullArgSpecEquals(_pickle.Pickler(io.BytesIO()).dump, [],
|
||||||
args_e=['self', 'obj'], formatted='(self, obj)')
|
posonlyargs_e=['self', 'obj'], formatted='(self, obj, /)')
|
||||||
|
|
||||||
self.assertFullArgSpecEquals(
|
self.assertFullArgSpecEquals(
|
||||||
os.stat,
|
os.stat,
|
||||||
|
|
|
@ -233,6 +233,18 @@ class RoundtripLegalSyntaxTestCase(unittest.TestCase):
|
||||||
self.check_suite("def f(*args, a, b = 5): pass")
|
self.check_suite("def f(*args, a, b = 5): pass")
|
||||||
self.check_suite("def f(*args, a, b = 5, **kwds): pass")
|
self.check_suite("def f(*args, a, b = 5, **kwds): pass")
|
||||||
|
|
||||||
|
# positional-only arguments
|
||||||
|
self.check_suite("def f(a, /): pass")
|
||||||
|
self.check_suite("def f(a, /,): pass")
|
||||||
|
self.check_suite("def f(a, b, /): pass")
|
||||||
|
self.check_suite("def f(a, b, /, c): pass")
|
||||||
|
self.check_suite("def f(a, b, /, c = 6): pass")
|
||||||
|
self.check_suite("def f(a, b, /, c, *, d): pass")
|
||||||
|
self.check_suite("def f(a, b, /, c = 1, *, d): pass")
|
||||||
|
self.check_suite("def f(a, b, /, c, *, d = 1): pass")
|
||||||
|
self.check_suite("def f(a, b=1, /, c=2, *, d = 3): pass")
|
||||||
|
self.check_suite("def f(a=0, b=1, /, c=2, *, d = 3): pass")
|
||||||
|
|
||||||
# function annotations
|
# function annotations
|
||||||
self.check_suite("def f(a: int): pass")
|
self.check_suite("def f(a: int): pass")
|
||||||
self.check_suite("def f(a: int = 5): pass")
|
self.check_suite("def f(a: int = 5): pass")
|
||||||
|
|
|
@ -0,0 +1,403 @@
|
||||||
|
"""Unit tests for the positional only argument syntax specified in PEP 570."""
|
||||||
|
|
||||||
|
import pickle
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from test.support import check_syntax_error
|
||||||
|
|
||||||
|
|
||||||
|
def global_pos_only_f(a, b, /):
|
||||||
|
return a, b
|
||||||
|
|
||||||
|
def global_pos_only_and_normal(a, /, b):
|
||||||
|
return a, b
|
||||||
|
|
||||||
|
def global_pos_only_defaults(a=1, /, b=2):
|
||||||
|
return a, b
|
||||||
|
|
||||||
|
|
||||||
|
class PositionalOnlyTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def assertRaisesSyntaxError(self, codestr, regex="invalid syntax"):
|
||||||
|
with self.assertRaisesRegex(SyntaxError, regex):
|
||||||
|
compile(codestr + "\n", "<test>", "single")
|
||||||
|
|
||||||
|
def test_invalid_syntax_errors(self):
|
||||||
|
check_syntax_error(self, "def f(a, b = 5, /, c): pass", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "def f(a = 5, b, /, c): pass", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "def f(a = 5, b=1, /, c, *, d=2): pass", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "def f(a = 5, b, /): pass", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "def f(*args, /): pass")
|
||||||
|
check_syntax_error(self, "def f(*args, a, /): pass")
|
||||||
|
check_syntax_error(self, "def f(**kwargs, /): pass")
|
||||||
|
check_syntax_error(self, "def f(/, a = 1): pass")
|
||||||
|
check_syntax_error(self, "def f(/, a): pass")
|
||||||
|
check_syntax_error(self, "def f(/): pass")
|
||||||
|
check_syntax_error(self, "def f(*, a, /): pass")
|
||||||
|
check_syntax_error(self, "def f(*, /, a): pass")
|
||||||
|
check_syntax_error(self, "def f(a, /, a): pass", "duplicate argument 'a' in function definition")
|
||||||
|
check_syntax_error(self, "def f(a, /, *, a): pass", "duplicate argument 'a' in function definition")
|
||||||
|
check_syntax_error(self, "def f(a, b/2, c): pass")
|
||||||
|
check_syntax_error(self, "def f(a, /, c, /): pass")
|
||||||
|
check_syntax_error(self, "def f(a, /, c, /, d): pass")
|
||||||
|
check_syntax_error(self, "def f(a, /, c, /, d, *, e): pass")
|
||||||
|
check_syntax_error(self, "def f(a, *, c, /, d, e): pass")
|
||||||
|
|
||||||
|
def test_invalid_syntax_errors_async(self):
|
||||||
|
check_syntax_error(self, "async def f(a, b = 5, /, c): pass", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "async def f(a = 5, b, /, c): pass", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "async def f(a = 5, b=1, /, c, d=2): pass", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "async def f(a = 5, b, /): pass", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "async def f(*args, /): pass")
|
||||||
|
check_syntax_error(self, "async def f(*args, a, /): pass")
|
||||||
|
check_syntax_error(self, "async def f(**kwargs, /): pass")
|
||||||
|
check_syntax_error(self, "async def f(/, a = 1): pass")
|
||||||
|
check_syntax_error(self, "async def f(/, a): pass")
|
||||||
|
check_syntax_error(self, "async def f(/): pass")
|
||||||
|
check_syntax_error(self, "async def f(*, a, /): pass")
|
||||||
|
check_syntax_error(self, "async def f(*, /, a): pass")
|
||||||
|
check_syntax_error(self, "async def f(a, /, a): pass", "duplicate argument 'a' in function definition")
|
||||||
|
check_syntax_error(self, "async def f(a, /, *, a): pass", "duplicate argument 'a' in function definition")
|
||||||
|
check_syntax_error(self, "async def f(a, b/2, c): pass")
|
||||||
|
check_syntax_error(self, "async def f(a, /, c, /): pass")
|
||||||
|
check_syntax_error(self, "async def f(a, /, c, /, d): pass")
|
||||||
|
check_syntax_error(self, "async def f(a, /, c, /, d, *, e): pass")
|
||||||
|
check_syntax_error(self, "async def f(a, *, c, /, d, e): pass")
|
||||||
|
|
||||||
|
def test_optional_positional_only_args(self):
|
||||||
|
def f(a, b=10, /, c=100):
|
||||||
|
return a + b + c
|
||||||
|
|
||||||
|
self.assertEqual(f(1, 2, 3), 6)
|
||||||
|
self.assertEqual(f(1, 2, c=3), 6)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'b'"):
|
||||||
|
f(1, b=2, c=3)
|
||||||
|
|
||||||
|
self.assertEqual(f(1, 2), 103)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'b'"):
|
||||||
|
f(1, b=2)
|
||||||
|
self.assertEqual(f(1, c=2), 13)
|
||||||
|
|
||||||
|
def f(a=1, b=10, /, c=100):
|
||||||
|
return a + b + c
|
||||||
|
|
||||||
|
self.assertEqual(f(1, 2, 3), 6)
|
||||||
|
self.assertEqual(f(1, 2, c=3), 6)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'b'"):
|
||||||
|
f(1, b=2, c=3)
|
||||||
|
|
||||||
|
self.assertEqual(f(1, 2), 103)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'b'"):
|
||||||
|
f(1, b=2)
|
||||||
|
self.assertEqual(f(1, c=2), 13)
|
||||||
|
|
||||||
|
def test_syntax_for_many_positional_only(self):
|
||||||
|
# more than 255 positional only arguments, should compile ok
|
||||||
|
fundef = "def f(%s, /):\n pass\n" % ', '.join('i%d' % i for i in range(300))
|
||||||
|
compile(fundef, "<test>", "single")
|
||||||
|
|
||||||
|
def test_pos_only_definition(self):
|
||||||
|
def f(a, b, c, /, d, e=1, *, f, g=2):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertEqual(2, f.__code__.co_argcount) # 2 "standard args"
|
||||||
|
self.assertEqual(3, f.__code__.co_posonlyargcount)
|
||||||
|
self.assertEqual((1,), f.__defaults__)
|
||||||
|
|
||||||
|
def f(a, b, c=1, /, d=2, e=3, *, f, g=4):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertEqual(2, f.__code__.co_argcount) # 2 "standard args"
|
||||||
|
self.assertEqual(3, f.__code__.co_posonlyargcount)
|
||||||
|
self.assertEqual((1, 2, 3), f.__defaults__)
|
||||||
|
|
||||||
|
def test_pos_only_call_via_unpacking(self):
|
||||||
|
def f(a, b, /):
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
self.assertEqual(f(*[1, 2]), 3)
|
||||||
|
|
||||||
|
def test_use_positional_as_keyword(self):
|
||||||
|
def f(a, /):
|
||||||
|
pass
|
||||||
|
expected = r"f\(\) got some positional-only arguments passed as keyword arguments: 'a'"
|
||||||
|
with self.assertRaisesRegex(TypeError, expected):
|
||||||
|
f(a=1)
|
||||||
|
|
||||||
|
def f(a, /, b):
|
||||||
|
pass
|
||||||
|
expected = r"f\(\) got some positional-only arguments passed as keyword arguments: 'a'"
|
||||||
|
with self.assertRaisesRegex(TypeError, expected):
|
||||||
|
f(a=1, b=2)
|
||||||
|
|
||||||
|
def f(a, b, /):
|
||||||
|
pass
|
||||||
|
expected = r"f\(\) got some positional-only arguments passed as keyword arguments: 'a, b'"
|
||||||
|
with self.assertRaisesRegex(TypeError, expected):
|
||||||
|
f(a=1, b=2)
|
||||||
|
|
||||||
|
def test_positional_only_and_arg_invalid_calls(self):
|
||||||
|
def f(a, b, /, c):
|
||||||
|
pass
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'c'"):
|
||||||
|
f(1, 2)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 2 required positional arguments: 'b' and 'c'"):
|
||||||
|
f(1)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 3 required positional arguments: 'a', 'b', and 'c'"):
|
||||||
|
f()
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) takes 3 positional arguments but 4 were given"):
|
||||||
|
f(1, 2, 3, 4)
|
||||||
|
|
||||||
|
def test_positional_only_and_optional_arg_invalid_calls(self):
|
||||||
|
def f(a, b, /, c=3):
|
||||||
|
pass
|
||||||
|
f(1, 2) # does not raise
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'b'"):
|
||||||
|
f(1)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 2 required positional arguments: 'a' and 'b'"):
|
||||||
|
f()
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) takes from 2 to 3 positional arguments but 4 were given"):
|
||||||
|
f(1, 2, 3, 4)
|
||||||
|
|
||||||
|
def test_positional_only_and_kwonlyargs_invalid_calls(self):
|
||||||
|
def f(a, b, /, c, *, d, e):
|
||||||
|
pass
|
||||||
|
f(1, 2, 3, d=1, e=2) # does not raise
|
||||||
|
with self.assertRaisesRegex(TypeError, r"missing 1 required keyword-only argument: 'd'"):
|
||||||
|
f(1, 2, 3, e=2)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"missing 2 required keyword-only arguments: 'd' and 'e'"):
|
||||||
|
f(1, 2, 3)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'c'"):
|
||||||
|
f(1, 2)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 2 required positional arguments: 'b' and 'c'"):
|
||||||
|
f(1)
|
||||||
|
with self.assertRaisesRegex(TypeError, r" missing 3 required positional arguments: 'a', 'b', and 'c'"):
|
||||||
|
f()
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) takes 3 positional arguments but 6 positional arguments "
|
||||||
|
r"\(and 2 keyword-only arguments\) were given"):
|
||||||
|
f(1, 2, 3, 4, 5, 6, d=7, e=8)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) got an unexpected keyword argument 'f'"):
|
||||||
|
f(1, 2, 3, d=1, e=4, f=56)
|
||||||
|
|
||||||
|
def test_positional_only_invalid_calls(self):
|
||||||
|
def f(a, b, /):
|
||||||
|
pass
|
||||||
|
f(1, 2) # does not raise
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'b'"):
|
||||||
|
f(1)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 2 required positional arguments: 'a' and 'b'"):
|
||||||
|
f()
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) takes 2 positional arguments but 3 were given"):
|
||||||
|
f(1, 2, 3)
|
||||||
|
|
||||||
|
def test_positional_only_with_optional_invalid_calls(self):
|
||||||
|
def f(a, b=2, /):
|
||||||
|
pass
|
||||||
|
f(1) # does not raise
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'a'"):
|
||||||
|
f()
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) takes from 1 to 2 positional arguments but 3 were given"):
|
||||||
|
f(1, 2, 3)
|
||||||
|
|
||||||
|
def test_no_standard_args_usage(self):
|
||||||
|
def f(a, b, /, *, c):
|
||||||
|
pass
|
||||||
|
|
||||||
|
f(1, 2, c=3)
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
f(1, b=2, c=3)
|
||||||
|
|
||||||
|
def test_change_default_pos_only(self):
|
||||||
|
def f(a, b=2, /, c=3):
|
||||||
|
return a + b + c
|
||||||
|
|
||||||
|
self.assertEqual((2,3), f.__defaults__)
|
||||||
|
f.__defaults__ = (1, 2, 3)
|
||||||
|
self.assertEqual(f(1, 2, 3), 6)
|
||||||
|
|
||||||
|
def test_lambdas(self):
|
||||||
|
x = lambda a, /, b: a + b
|
||||||
|
self.assertEqual(x(1,2), 3)
|
||||||
|
self.assertEqual(x(1,b=2), 3)
|
||||||
|
|
||||||
|
x = lambda a, /, b=2: a + b
|
||||||
|
self.assertEqual(x(1), 3)
|
||||||
|
|
||||||
|
x = lambda a, b, /: a + b
|
||||||
|
self.assertEqual(x(1, 2), 3)
|
||||||
|
|
||||||
|
x = lambda a, b, /, : a + b
|
||||||
|
self.assertEqual(x(1, 2), 3)
|
||||||
|
|
||||||
|
def test_invalid_syntax_lambda(self):
|
||||||
|
check_syntax_error(self, "lambda a, b = 5, /, c: None", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "lambda a = 5, b, /, c: None", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "lambda a = 5, b, /: None", "non-default argument follows default argument")
|
||||||
|
check_syntax_error(self, "lambda *args, /: None")
|
||||||
|
check_syntax_error(self, "lambda *args, a, /: None")
|
||||||
|
check_syntax_error(self, "lambda **kwargs, /: None")
|
||||||
|
check_syntax_error(self, "lambda /, a = 1: None")
|
||||||
|
check_syntax_error(self, "lambda /, a: None")
|
||||||
|
check_syntax_error(self, "lambda /: None")
|
||||||
|
check_syntax_error(self, "lambda *, a, /: None")
|
||||||
|
check_syntax_error(self, "lambda *, /, a: None")
|
||||||
|
check_syntax_error(self, "lambda a, /, a: None", "duplicate argument 'a' in function definition")
|
||||||
|
check_syntax_error(self, "lambda a, /, *, a: None", "duplicate argument 'a' in function definition")
|
||||||
|
check_syntax_error(self, "lambda a, /, b, /: None")
|
||||||
|
check_syntax_error(self, "lambda a, /, b, /, c: None")
|
||||||
|
check_syntax_error(self, "lambda a, /, b, /, c, *, d: None")
|
||||||
|
check_syntax_error(self, "lambda a, *, b, /, c: None")
|
||||||
|
|
||||||
|
def test_posonly_methods(self):
|
||||||
|
class Example:
|
||||||
|
def f(self, a, b, /):
|
||||||
|
return a, b
|
||||||
|
|
||||||
|
self.assertEqual(Example().f(1, 2), (1, 2))
|
||||||
|
self.assertEqual(Example.f(Example(), 1, 2), (1, 2))
|
||||||
|
self.assertRaises(TypeError, Example.f, 1, 2)
|
||||||
|
expected = r"f\(\) got some positional-only arguments passed as keyword arguments: 'b'"
|
||||||
|
with self.assertRaisesRegex(TypeError, expected):
|
||||||
|
Example().f(1, b=2)
|
||||||
|
|
||||||
|
def test_mangling(self):
|
||||||
|
class X:
|
||||||
|
def f(self, *, __a=42):
|
||||||
|
return __a
|
||||||
|
self.assertEqual(X().f(), 42)
|
||||||
|
|
||||||
|
def test_module_function(self):
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 2 required positional arguments: 'a' and 'b'"):
|
||||||
|
global_pos_only_f()
|
||||||
|
|
||||||
|
|
||||||
|
def test_closures(self):
|
||||||
|
def f(x,y):
|
||||||
|
def g(x2,/,y2):
|
||||||
|
return x + y + x2 + y2
|
||||||
|
return g
|
||||||
|
|
||||||
|
self.assertEqual(f(1,2)(3,4), 10)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"g\(\) missing 1 required positional argument: 'y2'"):
|
||||||
|
f(1,2)(3)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"g\(\) takes 2 positional arguments but 3 were given"):
|
||||||
|
f(1,2)(3,4,5)
|
||||||
|
|
||||||
|
def f(x,/,y):
|
||||||
|
def g(x2,y2):
|
||||||
|
return x + y + x2 + y2
|
||||||
|
return g
|
||||||
|
|
||||||
|
self.assertEqual(f(1,2)(3,4), 10)
|
||||||
|
|
||||||
|
def f(x,/,y):
|
||||||
|
def g(x2,/,y2):
|
||||||
|
return x + y + x2 + y2
|
||||||
|
return g
|
||||||
|
|
||||||
|
self.assertEqual(f(1,2)(3,4), 10)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"g\(\) missing 1 required positional argument: 'y2'"):
|
||||||
|
f(1,2)(3)
|
||||||
|
with self.assertRaisesRegex(TypeError, r"g\(\) takes 2 positional arguments but 3 were given"):
|
||||||
|
f(1,2)(3,4,5)
|
||||||
|
|
||||||
|
def test_same_keyword_as_positional_with_kwargs(self):
|
||||||
|
def f(something,/,**kwargs):
|
||||||
|
return (something, kwargs)
|
||||||
|
|
||||||
|
self.assertEqual(f(42, something=42), (42, {'something': 42}))
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) missing 1 required positional argument: 'something'"):
|
||||||
|
f(something=42)
|
||||||
|
|
||||||
|
self.assertEqual(f(42), (42, {}))
|
||||||
|
|
||||||
|
def test_mangling(self):
|
||||||
|
class X:
|
||||||
|
def f(self, __a=42, /):
|
||||||
|
return __a
|
||||||
|
|
||||||
|
def f2(self, __a=42, /, __b=43):
|
||||||
|
return (__a, __b)
|
||||||
|
|
||||||
|
def f3(self, __a=42, /, __b=43, *, __c=44):
|
||||||
|
return (__a, __b, __c)
|
||||||
|
|
||||||
|
self.assertEqual(X().f(), 42)
|
||||||
|
self.assertEqual(X().f2(), (42, 43))
|
||||||
|
self.assertEqual(X().f3(), (42, 43, 44))
|
||||||
|
|
||||||
|
def test_too_many_arguments(self):
|
||||||
|
# more than 255 positional-only arguments, should compile ok
|
||||||
|
fundef = "def f(%s, /):\n pass\n" % ', '.join('i%d' % i for i in range(300))
|
||||||
|
compile(fundef, "<test>", "single")
|
||||||
|
|
||||||
|
def test_serialization(self):
|
||||||
|
pickled_posonly = pickle.dumps(global_pos_only_f)
|
||||||
|
pickled_optional = pickle.dumps(global_pos_only_and_normal)
|
||||||
|
pickled_defaults = pickle.dumps(global_pos_only_defaults)
|
||||||
|
|
||||||
|
unpickled_posonly = pickle.loads(pickled_posonly)
|
||||||
|
unpickled_optional = pickle.loads(pickled_optional)
|
||||||
|
unpickled_defaults = pickle.loads(pickled_defaults)
|
||||||
|
|
||||||
|
self.assertEqual(unpickled_posonly(1,2), (1,2))
|
||||||
|
expected = r"global_pos_only_f\(\) got some positional-only arguments "\
|
||||||
|
r"passed as keyword arguments: 'a, b'"
|
||||||
|
with self.assertRaisesRegex(TypeError, expected):
|
||||||
|
unpickled_posonly(a=1,b=2)
|
||||||
|
|
||||||
|
self.assertEqual(unpickled_optional(1,2), (1,2))
|
||||||
|
expected = r"global_pos_only_and_normal\(\) got some positional-only arguments "\
|
||||||
|
r"passed as keyword arguments: 'a'"
|
||||||
|
with self.assertRaisesRegex(TypeError, expected):
|
||||||
|
unpickled_optional(a=1,b=2)
|
||||||
|
|
||||||
|
self.assertEqual(unpickled_defaults(), (1,2))
|
||||||
|
expected = r"global_pos_only_defaults\(\) got some positional-only arguments "\
|
||||||
|
r"passed as keyword arguments: 'a'"
|
||||||
|
with self.assertRaisesRegex(TypeError, expected):
|
||||||
|
unpickled_defaults(a=1,b=2)
|
||||||
|
|
||||||
|
def test_async(self):
|
||||||
|
|
||||||
|
async def f(a=1, /, b=2):
|
||||||
|
return a, b
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'a'"):
|
||||||
|
f(a=1, b=2)
|
||||||
|
|
||||||
|
def _check_call(*args, **kwargs):
|
||||||
|
try:
|
||||||
|
coro = f(*args, **kwargs)
|
||||||
|
coro.send(None)
|
||||||
|
except StopIteration as e:
|
||||||
|
result = e.value
|
||||||
|
self.assertEqual(result, (1, 2))
|
||||||
|
|
||||||
|
_check_call(1, 2)
|
||||||
|
_check_call(1, b=2)
|
||||||
|
_check_call(1)
|
||||||
|
_check_call()
|
||||||
|
|
||||||
|
def test_generator(self):
|
||||||
|
|
||||||
|
def f(a=1, /, b=2):
|
||||||
|
yield a, b
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(TypeError, r"f\(\) got some positional-only arguments passed as keyword arguments: 'a'"):
|
||||||
|
f(a=1, b=2)
|
||||||
|
|
||||||
|
gen = f(1, 2)
|
||||||
|
self.assertEqual(next(gen), (1, 2))
|
||||||
|
gen = f(1, b=2)
|
||||||
|
self.assertEqual(next(gen), (1, 2))
|
||||||
|
gen = f(1)
|
||||||
|
self.assertEqual(next(gen), (1, 2))
|
||||||
|
gen = f()
|
||||||
|
self.assertEqual(next(gen), (1, 2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
|
@ -263,7 +263,7 @@ def coroutine(func):
|
||||||
# TODO: Implement this in C.
|
# TODO: Implement this in C.
|
||||||
co = func.__code__
|
co = func.__code__
|
||||||
func.__code__ = CodeType(
|
func.__code__ = CodeType(
|
||||||
co.co_argcount, co.co_kwonlyargcount, co.co_nlocals,
|
co.co_argcount, co.co_posonlyargcount, co.co_kwonlyargcount, co.co_nlocals,
|
||||||
co.co_stacksize,
|
co.co_stacksize,
|
||||||
co.co_flags | 0x100, # 0x100 == CO_ITERABLE_COROUTINE
|
co.co_flags | 0x100, # 0x100 == CO_ITERABLE_COROUTINE
|
||||||
co.co_code,
|
co.co_code,
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Implement :pep:`570` (Python positional-only parameters). Patch by Pablo
|
||||||
|
Galindo.
|
|
@ -320,11 +320,11 @@ _PyFunction_FastCallDict(PyObject *func, PyObject *const *args, Py_ssize_t nargs
|
||||||
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
|
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
|
||||||
{
|
{
|
||||||
/* Fast paths */
|
/* Fast paths */
|
||||||
if (argdefs == NULL && co->co_argcount == nargs) {
|
if (argdefs == NULL && co->co_argcount + co->co_posonlyargcount == nargs) {
|
||||||
return function_code_fastcall(co, args, nargs, globals);
|
return function_code_fastcall(co, args, nargs, globals);
|
||||||
}
|
}
|
||||||
else if (nargs == 0 && argdefs != NULL
|
else if (nargs == 0 && argdefs != NULL
|
||||||
&& co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
|
&& co->co_argcount + co->co_posonlyargcount == PyTuple_GET_SIZE(argdefs)) {
|
||||||
/* function called with no arguments, but all parameters have
|
/* function called with no arguments, but all parameters have
|
||||||
a default value: use default values as arguments .*/
|
a default value: use default values as arguments .*/
|
||||||
args = _PyTuple_ITEMS(argdefs);
|
args = _PyTuple_ITEMS(argdefs);
|
||||||
|
@ -406,11 +406,11 @@ _PyFunction_FastCallKeywords(PyObject *func, PyObject *const *stack,
|
||||||
if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
|
if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
|
||||||
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
|
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
|
||||||
{
|
{
|
||||||
if (argdefs == NULL && co->co_argcount == nargs) {
|
if (argdefs == NULL && co->co_argcount + co->co_posonlyargcount== nargs) {
|
||||||
return function_code_fastcall(co, stack, nargs, globals);
|
return function_code_fastcall(co, stack, nargs, globals);
|
||||||
}
|
}
|
||||||
else if (nargs == 0 && argdefs != NULL
|
else if (nargs == 0 && argdefs != NULL
|
||||||
&& co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
|
&& co->co_argcount + co->co_posonlyargcount == PyTuple_GET_SIZE(argdefs)) {
|
||||||
/* function called with no arguments, but all parameters have
|
/* function called with no arguments, but all parameters have
|
||||||
a default value: use default values as arguments .*/
|
a default value: use default values as arguments .*/
|
||||||
stack = _PyTuple_ITEMS(argdefs);
|
stack = _PyTuple_ITEMS(argdefs);
|
||||||
|
|
|
@ -96,7 +96,7 @@ intern_string_constants(PyObject *tuple)
|
||||||
|
|
||||||
|
|
||||||
PyCodeObject *
|
PyCodeObject *
|
||||||
PyCode_New(int argcount, int kwonlyargcount,
|
PyCode_New(int argcount, int posonlyargcount, int kwonlyargcount,
|
||||||
int nlocals, int stacksize, int flags,
|
int nlocals, int stacksize, int flags,
|
||||||
PyObject *code, PyObject *consts, PyObject *names,
|
PyObject *code, PyObject *consts, PyObject *names,
|
||||||
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
|
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
|
||||||
|
@ -108,8 +108,8 @@ PyCode_New(int argcount, int kwonlyargcount,
|
||||||
Py_ssize_t i, n_cellvars, n_varnames, total_args;
|
Py_ssize_t i, n_cellvars, n_varnames, total_args;
|
||||||
|
|
||||||
/* Check argument types */
|
/* Check argument types */
|
||||||
if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 ||
|
if (argcount < 0 || posonlyargcount < 0 || kwonlyargcount < 0 ||
|
||||||
code == NULL || !PyBytes_Check(code) ||
|
nlocals < 0 || code == NULL || !PyBytes_Check(code) ||
|
||||||
consts == NULL || !PyTuple_Check(consts) ||
|
consts == NULL || !PyTuple_Check(consts) ||
|
||||||
names == NULL || !PyTuple_Check(names) ||
|
names == NULL || !PyTuple_Check(names) ||
|
||||||
varnames == NULL || !PyTuple_Check(varnames) ||
|
varnames == NULL || !PyTuple_Check(varnames) ||
|
||||||
|
@ -141,9 +141,11 @@ PyCode_New(int argcount, int kwonlyargcount,
|
||||||
}
|
}
|
||||||
|
|
||||||
n_varnames = PyTuple_GET_SIZE(varnames);
|
n_varnames = PyTuple_GET_SIZE(varnames);
|
||||||
if (argcount <= n_varnames && kwonlyargcount <= n_varnames) {
|
if (posonlyargcount + argcount <= n_varnames
|
||||||
|
&& kwonlyargcount <= n_varnames) {
|
||||||
/* Never overflows. */
|
/* Never overflows. */
|
||||||
total_args = (Py_ssize_t)argcount + (Py_ssize_t)kwonlyargcount +
|
total_args = (Py_ssize_t)posonlyargcount + (Py_ssize_t)argcount
|
||||||
|
+ (Py_ssize_t)kwonlyargcount +
|
||||||
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
|
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -193,6 +195,7 @@ PyCode_New(int argcount, int kwonlyargcount,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
co->co_argcount = argcount;
|
co->co_argcount = argcount;
|
||||||
|
co->co_posonlyargcount = posonlyargcount;
|
||||||
co->co_kwonlyargcount = kwonlyargcount;
|
co->co_kwonlyargcount = kwonlyargcount;
|
||||||
co->co_nlocals = nlocals;
|
co->co_nlocals = nlocals;
|
||||||
co->co_stacksize = stacksize;
|
co->co_stacksize = stacksize;
|
||||||
|
@ -249,6 +252,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
result = PyCode_New(0, /* argcount */
|
result = PyCode_New(0, /* argcount */
|
||||||
|
0, /* posonlyargcount */
|
||||||
0, /* kwonlyargcount */
|
0, /* kwonlyargcount */
|
||||||
0, /* nlocals */
|
0, /* nlocals */
|
||||||
0, /* stacksize */
|
0, /* stacksize */
|
||||||
|
@ -275,6 +279,7 @@ failed:
|
||||||
|
|
||||||
static PyMemberDef code_memberlist[] = {
|
static PyMemberDef code_memberlist[] = {
|
||||||
{"co_argcount", T_INT, OFF(co_argcount), READONLY},
|
{"co_argcount", T_INT, OFF(co_argcount), READONLY},
|
||||||
|
{"co_posonlyargcount", T_INT, OFF(co_posonlyargcount), READONLY},
|
||||||
{"co_kwonlyargcount", T_INT, OFF(co_kwonlyargcount), READONLY},
|
{"co_kwonlyargcount", T_INT, OFF(co_kwonlyargcount), READONLY},
|
||||||
{"co_nlocals", T_INT, OFF(co_nlocals), READONLY},
|
{"co_nlocals", T_INT, OFF(co_nlocals), READONLY},
|
||||||
{"co_stacksize",T_INT, OFF(co_stacksize), READONLY},
|
{"co_stacksize",T_INT, OFF(co_stacksize), READONLY},
|
||||||
|
@ -335,9 +340,9 @@ validate_and_copy_tuple(PyObject *tup)
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(code_doc,
|
PyDoc_STRVAR(code_doc,
|
||||||
"code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,\n\
|
"code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n\
|
||||||
constants, names, varnames, filename, name, firstlineno,\n\
|
flags, codestring, constants, names, varnames, filename, name,\n\
|
||||||
lnotab[, freevars[, cellvars]])\n\
|
firstlineno, lnotab[, freevars[, cellvars]])\n\
|
||||||
\n\
|
\n\
|
||||||
Create a code object. Not for the faint of heart.");
|
Create a code object. Not for the faint of heart.");
|
||||||
|
|
||||||
|
@ -345,6 +350,7 @@ static PyObject *
|
||||||
code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
{
|
{
|
||||||
int argcount;
|
int argcount;
|
||||||
|
int posonlyargcount;
|
||||||
int kwonlyargcount;
|
int kwonlyargcount;
|
||||||
int nlocals;
|
int nlocals;
|
||||||
int stacksize;
|
int stacksize;
|
||||||
|
@ -361,8 +367,8 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
int firstlineno;
|
int firstlineno;
|
||||||
PyObject *lnotab;
|
PyObject *lnotab;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "iiiiiSO!O!O!UUiS|O!O!:code",
|
if (!PyArg_ParseTuple(args, "iiiiiiSO!O!O!UUiS|O!O!:code",
|
||||||
&argcount, &kwonlyargcount,
|
&argcount, &posonlyargcount, &kwonlyargcount,
|
||||||
&nlocals, &stacksize, &flags,
|
&nlocals, &stacksize, &flags,
|
||||||
&code,
|
&code,
|
||||||
&PyTuple_Type, &consts,
|
&PyTuple_Type, &consts,
|
||||||
|
@ -381,6 +387,13 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (posonlyargcount < 0) {
|
||||||
|
PyErr_SetString(
|
||||||
|
PyExc_ValueError,
|
||||||
|
"code: posonlyargcount must not be negative");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if (kwonlyargcount < 0) {
|
if (kwonlyargcount < 0) {
|
||||||
PyErr_SetString(
|
PyErr_SetString(
|
||||||
PyExc_ValueError,
|
PyExc_ValueError,
|
||||||
|
@ -413,7 +426,7 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
if (ourcellvars == NULL)
|
if (ourcellvars == NULL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
co = (PyObject *)PyCode_New(argcount, kwonlyargcount,
|
co = (PyObject *)PyCode_New(argcount, posonlyargcount, kwonlyargcount,
|
||||||
nlocals, stacksize, flags,
|
nlocals, stacksize, flags,
|
||||||
code, consts, ournames, ourvarnames,
|
code, consts, ournames, ourvarnames,
|
||||||
ourfreevars, ourcellvars, filename,
|
ourfreevars, ourcellvars, filename,
|
||||||
|
@ -645,9 +658,11 @@ code_richcompare(PyObject *self, PyObject *other, int op)
|
||||||
cp = (PyCodeObject *)other;
|
cp = (PyCodeObject *)other;
|
||||||
|
|
||||||
eq = PyObject_RichCompareBool(co->co_name, cp->co_name, Py_EQ);
|
eq = PyObject_RichCompareBool(co->co_name, cp->co_name, Py_EQ);
|
||||||
if (eq <= 0) goto unequal;
|
if (!eq) goto unequal;
|
||||||
eq = co->co_argcount == cp->co_argcount;
|
eq = co->co_argcount == cp->co_argcount;
|
||||||
if (!eq) goto unequal;
|
if (!eq) goto unequal;
|
||||||
|
eq = co->co_posonlyargcount == cp->co_posonlyargcount;
|
||||||
|
if (!eq) goto unequal;
|
||||||
eq = co->co_kwonlyargcount == cp->co_kwonlyargcount;
|
eq = co->co_kwonlyargcount == cp->co_kwonlyargcount;
|
||||||
if (!eq) goto unequal;
|
if (!eq) goto unequal;
|
||||||
eq = co->co_nlocals == cp->co_nlocals;
|
eq = co->co_nlocals == cp->co_nlocals;
|
||||||
|
@ -720,7 +735,7 @@ code_hash(PyCodeObject *co)
|
||||||
h6 = PyObject_Hash(co->co_cellvars);
|
h6 = PyObject_Hash(co->co_cellvars);
|
||||||
if (h6 == -1) return -1;
|
if (h6 == -1) return -1;
|
||||||
h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^
|
h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^
|
||||||
co->co_argcount ^ co->co_kwonlyargcount ^
|
co->co_argcount ^ co->co_posonlyargcount ^ co->co_kwonlyargcount ^
|
||||||
co->co_nlocals ^ co->co_flags;
|
co->co_nlocals ^ co->co_flags;
|
||||||
if (h == -1) h = -2;
|
if (h == -1) h = -2;
|
||||||
return h;
|
return h;
|
||||||
|
|
|
@ -1139,7 +1139,7 @@ static PYC_MAGIC magic_values[] = {
|
||||||
{ 3320, 3351, L"3.5" },
|
{ 3320, 3351, L"3.5" },
|
||||||
{ 3360, 3379, L"3.6" },
|
{ 3360, 3379, L"3.6" },
|
||||||
{ 3390, 3399, L"3.7" },
|
{ 3390, 3399, L"3.7" },
|
||||||
{ 3400, 3409, L"3.8" },
|
{ 3400, 3410, L"3.8" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -111,8 +111,8 @@ module Python
|
||||||
excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
|
excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
|
||||||
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
||||||
|
|
||||||
arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults,
|
arguments = (arg* args, arg* posonlyargs, arg? vararg, arg* kwonlyargs,
|
||||||
arg? kwarg, expr* defaults)
|
expr* kw_defaults, arg? kwarg, expr* defaults)
|
||||||
|
|
||||||
arg = (identifier arg, expr? annotation, string? type_comment)
|
arg = (identifier arg, expr? annotation, string? type_comment)
|
||||||
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
||||||
|
|
|
@ -469,6 +469,7 @@ static char *ExceptHandler_fields[]={
|
||||||
};
|
};
|
||||||
static PyTypeObject *arguments_type;
|
static PyTypeObject *arguments_type;
|
||||||
static PyObject* ast2obj_arguments(void*);
|
static PyObject* ast2obj_arguments(void*);
|
||||||
|
_Py_IDENTIFIER(posonlyargs);
|
||||||
_Py_IDENTIFIER(vararg);
|
_Py_IDENTIFIER(vararg);
|
||||||
_Py_IDENTIFIER(kwonlyargs);
|
_Py_IDENTIFIER(kwonlyargs);
|
||||||
_Py_IDENTIFIER(kw_defaults);
|
_Py_IDENTIFIER(kw_defaults);
|
||||||
|
@ -476,6 +477,7 @@ _Py_IDENTIFIER(kwarg);
|
||||||
_Py_IDENTIFIER(defaults);
|
_Py_IDENTIFIER(defaults);
|
||||||
static char *arguments_fields[]={
|
static char *arguments_fields[]={
|
||||||
"args",
|
"args",
|
||||||
|
"posonlyargs",
|
||||||
"vararg",
|
"vararg",
|
||||||
"kwonlyargs",
|
"kwonlyargs",
|
||||||
"kw_defaults",
|
"kw_defaults",
|
||||||
|
@ -1141,7 +1143,7 @@ static int init_types(void)
|
||||||
ExceptHandler_type = make_type("ExceptHandler", excepthandler_type,
|
ExceptHandler_type = make_type("ExceptHandler", excepthandler_type,
|
||||||
ExceptHandler_fields, 3);
|
ExceptHandler_fields, 3);
|
||||||
if (!ExceptHandler_type) return 0;
|
if (!ExceptHandler_type) return 0;
|
||||||
arguments_type = make_type("arguments", &AST_type, arguments_fields, 6);
|
arguments_type = make_type("arguments", &AST_type, arguments_fields, 7);
|
||||||
if (!arguments_type) return 0;
|
if (!arguments_type) return 0;
|
||||||
if (!add_attributes(arguments_type, NULL, 0)) return 0;
|
if (!add_attributes(arguments_type, NULL, 0)) return 0;
|
||||||
arg_type = make_type("arg", &AST_type, arg_fields, 3);
|
arg_type = make_type("arg", &AST_type, arg_fields, 3);
|
||||||
|
@ -2569,14 +2571,16 @@ ExceptHandler(expr_ty type, identifier name, asdl_seq * body, int lineno, int
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments_ty
|
arguments_ty
|
||||||
arguments(asdl_seq * args, arg_ty vararg, asdl_seq * kwonlyargs, asdl_seq *
|
arguments(asdl_seq * args, asdl_seq * posonlyargs, arg_ty vararg, asdl_seq *
|
||||||
kw_defaults, arg_ty kwarg, asdl_seq * defaults, PyArena *arena)
|
kwonlyargs, asdl_seq * kw_defaults, arg_ty kwarg, asdl_seq *
|
||||||
|
defaults, PyArena *arena)
|
||||||
{
|
{
|
||||||
arguments_ty p;
|
arguments_ty p;
|
||||||
p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p));
|
p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p));
|
||||||
if (!p)
|
if (!p)
|
||||||
return NULL;
|
return NULL;
|
||||||
p->args = args;
|
p->args = args;
|
||||||
|
p->posonlyargs = posonlyargs;
|
||||||
p->vararg = vararg;
|
p->vararg = vararg;
|
||||||
p->kwonlyargs = kwonlyargs;
|
p->kwonlyargs = kwonlyargs;
|
||||||
p->kw_defaults = kw_defaults;
|
p->kw_defaults = kw_defaults;
|
||||||
|
@ -3954,6 +3958,11 @@ ast2obj_arguments(void* _o)
|
||||||
if (_PyObject_SetAttrId(result, &PyId_args, value) == -1)
|
if (_PyObject_SetAttrId(result, &PyId_args, value) == -1)
|
||||||
goto failed;
|
goto failed;
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
|
value = ast2obj_list(o->posonlyargs, ast2obj_arg);
|
||||||
|
if (!value) goto failed;
|
||||||
|
if (_PyObject_SetAttrId(result, &PyId_posonlyargs, value) == -1)
|
||||||
|
goto failed;
|
||||||
|
Py_DECREF(value);
|
||||||
value = ast2obj_arg(o->vararg);
|
value = ast2obj_arg(o->vararg);
|
||||||
if (!value) goto failed;
|
if (!value) goto failed;
|
||||||
if (_PyObject_SetAttrId(result, &PyId_vararg, value) == -1)
|
if (_PyObject_SetAttrId(result, &PyId_vararg, value) == -1)
|
||||||
|
@ -8267,6 +8276,7 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
|
||||||
{
|
{
|
||||||
PyObject* tmp = NULL;
|
PyObject* tmp = NULL;
|
||||||
asdl_seq* args;
|
asdl_seq* args;
|
||||||
|
asdl_seq* posonlyargs;
|
||||||
arg_ty vararg;
|
arg_ty vararg;
|
||||||
asdl_seq* kwonlyargs;
|
asdl_seq* kwonlyargs;
|
||||||
asdl_seq* kw_defaults;
|
asdl_seq* kw_defaults;
|
||||||
|
@ -8303,6 +8313,36 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
|
||||||
}
|
}
|
||||||
Py_CLEAR(tmp);
|
Py_CLEAR(tmp);
|
||||||
}
|
}
|
||||||
|
if (_PyObject_LookupAttrId(obj, &PyId_posonlyargs, &tmp) < 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (tmp == NULL) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "required field \"posonlyargs\" missing from arguments");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int res;
|
||||||
|
Py_ssize_t len;
|
||||||
|
Py_ssize_t i;
|
||||||
|
if (!PyList_Check(tmp)) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "arguments field \"posonlyargs\" must be a list, not a %.200s", tmp->ob_type->tp_name);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
len = PyList_GET_SIZE(tmp);
|
||||||
|
posonlyargs = _Py_asdl_seq_new(len, arena);
|
||||||
|
if (posonlyargs == NULL) goto failed;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
arg_ty val;
|
||||||
|
res = obj2ast_arg(PyList_GET_ITEM(tmp, i), &val, arena);
|
||||||
|
if (res != 0) goto failed;
|
||||||
|
if (len != PyList_GET_SIZE(tmp)) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "arguments field \"posonlyargs\" changed size during iteration");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
asdl_seq_SET(posonlyargs, i, val);
|
||||||
|
}
|
||||||
|
Py_CLEAR(tmp);
|
||||||
|
}
|
||||||
if (_PyObject_LookupAttrId(obj, &PyId_vararg, &tmp) < 0) {
|
if (_PyObject_LookupAttrId(obj, &PyId_vararg, &tmp) < 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -8419,8 +8459,8 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
|
||||||
}
|
}
|
||||||
Py_CLEAR(tmp);
|
Py_CLEAR(tmp);
|
||||||
}
|
}
|
||||||
*out = arguments(args, vararg, kwonlyargs, kw_defaults, kwarg, defaults,
|
*out = arguments(args, posonlyargs, vararg, kwonlyargs, kw_defaults, kwarg,
|
||||||
arena);
|
defaults, arena);
|
||||||
return 0;
|
return 0;
|
||||||
failed:
|
failed:
|
||||||
Py_XDECREF(tmp);
|
Py_XDECREF(tmp);
|
||||||
|
|
98
Python/ast.c
98
Python/ast.c
|
@ -110,8 +110,9 @@ expr_context_name(expr_context_ty ctx)
|
||||||
static int
|
static int
|
||||||
validate_arguments(arguments_ty args)
|
validate_arguments(arguments_ty args)
|
||||||
{
|
{
|
||||||
if (!validate_args(args->args))
|
if (!validate_args(args->posonlyargs) || !validate_args(args->args)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
if (args->vararg && args->vararg->annotation
|
if (args->vararg && args->vararg->annotation
|
||||||
&& !validate_expr(args->vararg->annotation, Load)) {
|
&& !validate_expr(args->vararg->annotation, Load)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1431,31 +1432,73 @@ ast_for_arguments(struct compiling *c, const node *n)
|
||||||
and varargslist (lambda definition).
|
and varargslist (lambda definition).
|
||||||
|
|
||||||
parameters: '(' [typedargslist] ')'
|
parameters: '(' [typedargslist] ')'
|
||||||
typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* [',' [
|
|
||||||
'*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]]
|
The following definition for typedarglist is equivalent to this set of rules:
|
||||||
| '**' tfpdef [',']]]
|
|
||||||
| '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]]
|
arguments = argument (',' [TYPE_COMMENT] argument)*
|
||||||
| '**' tfpdef [','])
|
argument = tfpdef ['=' test]
|
||||||
|
kwargs = '**' tfpdef [','] [TYPE_COMMENT]
|
||||||
|
args = '*' [tfpdef]
|
||||||
|
kwonly_kwargs = (',' [TYPE_COMMENT] argument)* (TYPE_COMMENT | [','
|
||||||
|
[TYPE_COMMENT] [kwargs]])
|
||||||
|
args_kwonly_kwargs = args kwonly_kwargs | kwargs
|
||||||
|
poskeyword_args_kwonly_kwargs = arguments ( TYPE_COMMENT | [','
|
||||||
|
[TYPE_COMMENT] [args_kwonly_kwargs]])
|
||||||
|
typedargslist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs
|
||||||
|
typedarglist = (arguments ',' [TYPE_COMMENT] '/' [',' [[TYPE_COMMENT]
|
||||||
|
typedargslist_no_posonly]])|(typedargslist_no_posonly)"
|
||||||
|
|
||||||
|
typedargslist: ( (tfpdef ['=' test] (',' [TYPE_COMMENT] tfpdef ['=' test])*
|
||||||
|
',' [TYPE_COMMENT] '/' [',' [ [TYPE_COMMENT] tfpdef ['=' test] ( ','
|
||||||
|
[TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] [ '*'
|
||||||
|
[tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [','
|
||||||
|
[TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]]) | '**' tfpdef [',']
|
||||||
|
[TYPE_COMMENT]]]) | '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])*
|
||||||
|
(TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]]) |
|
||||||
|
'**' tfpdef [','] [TYPE_COMMENT]]] ) | (tfpdef ['=' test] (','
|
||||||
|
[TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] [ '*'
|
||||||
|
[tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [','
|
||||||
|
[TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]]) | '**' tfpdef [',']
|
||||||
|
[TYPE_COMMENT]]]) | '*' [tfpdef] (',' [TYPE_COMMENT] tfpdef ['=' test])*
|
||||||
|
(TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]]) |
|
||||||
|
'**' tfpdef [','] [TYPE_COMMENT]))
|
||||||
|
|
||||||
tfpdef: NAME [':' test]
|
tfpdef: NAME [':' test]
|
||||||
varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
|
|
||||||
'*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
The following definition for varargslist is equivalent to this set of rules:
|
||||||
| '**' vfpdef [',']]]
|
|
||||||
| '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
arguments = argument (',' argument )*
|
||||||
| '**' vfpdef [',']
|
argument = vfpdef ['=' test]
|
||||||
)
|
kwargs = '**' vfpdef [',']
|
||||||
|
args = '*' [vfpdef]
|
||||||
|
kwonly_kwargs = (',' argument )* [',' [kwargs]]
|
||||||
|
args_kwonly_kwargs = args kwonly_kwargs | kwargs
|
||||||
|
poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]]
|
||||||
|
vararglist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs
|
||||||
|
varargslist = arguments ',' '/' [','[(vararglist_no_posonly)]] |
|
||||||
|
(vararglist_no_posonly)
|
||||||
|
|
||||||
|
varargslist: vfpdef ['=' test ](',' vfpdef ['=' test])* ',' '/' [',' [ (vfpdef ['='
|
||||||
|
test] (',' vfpdef ['=' test])* [',' [ '*' [vfpdef] (',' vfpdef ['=' test])* [','
|
||||||
|
['**' vfpdef [',']]] | '**' vfpdef [',']]] | '*' [vfpdef] (',' vfpdef ['=' test])*
|
||||||
|
[',' ['**' vfpdef [',']]] | '**' vfpdef [',']) ]] | (vfpdef ['=' test] (',' vfpdef
|
||||||
|
['=' test])* [',' [ '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
||||||
|
| '**' vfpdef [',']]] | '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef
|
||||||
|
[',']]] | '**' vfpdef [','])
|
||||||
|
|
||||||
vfpdef: NAME
|
vfpdef: NAME
|
||||||
|
|
||||||
*/
|
*/
|
||||||
int i, j, k, nposargs = 0, nkwonlyargs = 0;
|
int i, j, k, l, nposonlyargs=0, nposargs = 0, nkwonlyargs = 0;
|
||||||
int nposdefaults = 0, found_default = 0;
|
int nposdefaults = 0, found_default = 0;
|
||||||
asdl_seq *posargs, *posdefaults, *kwonlyargs, *kwdefaults;
|
asdl_seq *posonlyargs, *posargs, *posdefaults, *kwonlyargs, *kwdefaults;
|
||||||
arg_ty vararg = NULL, kwarg = NULL;
|
arg_ty vararg = NULL, kwarg = NULL;
|
||||||
arg_ty arg = NULL;
|
arg_ty arg = NULL;
|
||||||
node *ch;
|
node *ch;
|
||||||
|
|
||||||
if (TYPE(n) == parameters) {
|
if (TYPE(n) == parameters) {
|
||||||
if (NCH(n) == 2) /* () as argument list */
|
if (NCH(n) == 2) /* () as argument list */
|
||||||
return arguments(NULL, NULL, NULL, NULL, NULL, NULL, c->c_arena);
|
return arguments(NULL, NULL, NULL, NULL, NULL, NULL, NULL, c->c_arena);
|
||||||
n = CHILD(n, 1);
|
n = CHILD(n, 1);
|
||||||
}
|
}
|
||||||
assert(TYPE(n) == typedargslist || TYPE(n) == varargslist);
|
assert(TYPE(n) == typedargslist || TYPE(n) == varargslist);
|
||||||
|
@ -1479,6 +1522,10 @@ ast_for_arguments(struct compiling *c, const node *n)
|
||||||
if (TYPE(ch) == DOUBLESTAR) break;
|
if (TYPE(ch) == DOUBLESTAR) break;
|
||||||
if (TYPE(ch) == vfpdef || TYPE(ch) == tfpdef) nposargs++;
|
if (TYPE(ch) == vfpdef || TYPE(ch) == tfpdef) nposargs++;
|
||||||
if (TYPE(ch) == EQUAL) nposdefaults++;
|
if (TYPE(ch) == EQUAL) nposdefaults++;
|
||||||
|
if (TYPE(ch) == SLASH ) {
|
||||||
|
nposonlyargs = nposargs;
|
||||||
|
nposargs = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* count the number of keyword only args &
|
/* count the number of keyword only args &
|
||||||
defaults for keyword only args */
|
defaults for keyword only args */
|
||||||
|
@ -1487,6 +1534,10 @@ ast_for_arguments(struct compiling *c, const node *n)
|
||||||
if (TYPE(ch) == DOUBLESTAR) break;
|
if (TYPE(ch) == DOUBLESTAR) break;
|
||||||
if (TYPE(ch) == tfpdef || TYPE(ch) == vfpdef) nkwonlyargs++;
|
if (TYPE(ch) == tfpdef || TYPE(ch) == vfpdef) nkwonlyargs++;
|
||||||
}
|
}
|
||||||
|
posonlyargs = (nposonlyargs ? _Py_asdl_seq_new(nposonlyargs, c->c_arena) : NULL);
|
||||||
|
if (!posonlyargs && nposonlyargs) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
posargs = (nposargs ? _Py_asdl_seq_new(nposargs, c->c_arena) : NULL);
|
posargs = (nposargs ? _Py_asdl_seq_new(nposargs, c->c_arena) : NULL);
|
||||||
if (!posargs && nposargs)
|
if (!posargs && nposargs)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1512,6 +1563,7 @@ ast_for_arguments(struct compiling *c, const node *n)
|
||||||
i = 0;
|
i = 0;
|
||||||
j = 0; /* index for defaults */
|
j = 0; /* index for defaults */
|
||||||
k = 0; /* index for args */
|
k = 0; /* index for args */
|
||||||
|
l = 0; /* index for posonlyargs */
|
||||||
while (i < NCH(n)) {
|
while (i < NCH(n)) {
|
||||||
ch = CHILD(n, i);
|
ch = CHILD(n, i);
|
||||||
switch (TYPE(ch)) {
|
switch (TYPE(ch)) {
|
||||||
|
@ -1537,11 +1589,23 @@ ast_for_arguments(struct compiling *c, const node *n)
|
||||||
arg = ast_for_arg(c, ch);
|
arg = ast_for_arg(c, ch);
|
||||||
if (!arg)
|
if (!arg)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (l < nposonlyargs) {
|
||||||
|
asdl_seq_SET(posonlyargs, l++, arg);
|
||||||
|
} else {
|
||||||
asdl_seq_SET(posargs, k++, arg);
|
asdl_seq_SET(posargs, k++, arg);
|
||||||
|
}
|
||||||
i += 1; /* the name */
|
i += 1; /* the name */
|
||||||
if (i < NCH(n) && TYPE(CHILD(n, i)) == COMMA)
|
if (i < NCH(n) && TYPE(CHILD(n, i)) == COMMA)
|
||||||
i += 1; /* the comma, if present */
|
i += 1; /* the comma, if present */
|
||||||
break;
|
break;
|
||||||
|
case SLASH:
|
||||||
|
/* Advance the slash and the comma. If there are more names
|
||||||
|
* after the slash there will be a comma so we are advancing
|
||||||
|
* the correct number of nodes. If the slash is the last item,
|
||||||
|
* we will be advancing an extra token but then * i > NCH(n)
|
||||||
|
* and the enclosing while will finish correctly. */
|
||||||
|
i += 2;
|
||||||
|
break;
|
||||||
case STAR:
|
case STAR:
|
||||||
if (i+1 >= NCH(n) ||
|
if (i+1 >= NCH(n) ||
|
||||||
(i+2 == NCH(n) && (TYPE(CHILD(n, i+1)) == COMMA
|
(i+2 == NCH(n) && (TYPE(CHILD(n, i+1)) == COMMA
|
||||||
|
@ -1621,7 +1685,7 @@ ast_for_arguments(struct compiling *c, const node *n)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return arguments(posargs, vararg, kwonlyargs, kwdefaults, kwarg, posdefaults, c->c_arena);
|
return arguments(posargs, posonlyargs, vararg, kwonlyargs, kwdefaults, kwarg, posdefaults, c->c_arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
static expr_ty
|
static expr_ty
|
||||||
|
@ -1909,7 +1973,7 @@ ast_for_lambdef(struct compiling *c, const node *n)
|
||||||
expr_ty expression;
|
expr_ty expression;
|
||||||
|
|
||||||
if (NCH(n) == 3) {
|
if (NCH(n) == 3) {
|
||||||
args = arguments(NULL, NULL, NULL, NULL, NULL, NULL, c->c_arena);
|
args = arguments(NULL, NULL, NULL, NULL, NULL, NULL, NULL, c->c_arena);
|
||||||
if (!args)
|
if (!args)
|
||||||
return NULL;
|
return NULL;
|
||||||
expression = ast_for_expr(c, CHILD(n, 2));
|
expression = ast_for_expr(c, CHILD(n, 2));
|
||||||
|
|
120
Python/ceval.c
120
Python/ceval.c
|
@ -3694,10 +3694,10 @@ missing_arguments(PyCodeObject *co, Py_ssize_t missing, Py_ssize_t defcount,
|
||||||
return;
|
return;
|
||||||
if (positional) {
|
if (positional) {
|
||||||
start = 0;
|
start = 0;
|
||||||
end = co->co_argcount - defcount;
|
end = co->co_posonlyargcount + co->co_argcount - defcount;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
start = co->co_argcount;
|
start = co->co_posonlyargcount + co->co_argcount;
|
||||||
end = start + co->co_kwonlyargcount;
|
end = start + co->co_kwonlyargcount;
|
||||||
}
|
}
|
||||||
for (i = start; i < end; i++) {
|
for (i = start; i < end; i++) {
|
||||||
|
@ -3724,23 +3724,25 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
|
||||||
Py_ssize_t kwonly_given = 0;
|
Py_ssize_t kwonly_given = 0;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
PyObject *sig, *kwonly_sig;
|
PyObject *sig, *kwonly_sig;
|
||||||
|
Py_ssize_t co_posonlyargcount = co->co_posonlyargcount;
|
||||||
Py_ssize_t co_argcount = co->co_argcount;
|
Py_ssize_t co_argcount = co->co_argcount;
|
||||||
|
Py_ssize_t total_positional = co_argcount + co_posonlyargcount;
|
||||||
|
|
||||||
assert((co->co_flags & CO_VARARGS) == 0);
|
assert((co->co_flags & CO_VARARGS) == 0);
|
||||||
/* Count missing keyword-only args. */
|
/* Count missing keyword-only args. */
|
||||||
for (i = co_argcount; i < co_argcount + co->co_kwonlyargcount; i++) {
|
for (i = total_positional; i < total_positional + co->co_kwonlyargcount; i++) {
|
||||||
if (GETLOCAL(i) != NULL) {
|
if (GETLOCAL(i) != NULL) {
|
||||||
kwonly_given++;
|
kwonly_given++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (defcount) {
|
if (defcount) {
|
||||||
Py_ssize_t atleast = co_argcount - defcount;
|
Py_ssize_t atleast = total_positional - defcount;
|
||||||
plural = 1;
|
plural = 1;
|
||||||
sig = PyUnicode_FromFormat("from %zd to %zd", atleast, co_argcount);
|
sig = PyUnicode_FromFormat("from %zd to %zd", atleast, total_positional);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
plural = (co_argcount != 1);
|
plural = (total_positional != 1);
|
||||||
sig = PyUnicode_FromFormat("%zd", co_argcount);
|
sig = PyUnicode_FromFormat("%zd", total_positional);
|
||||||
}
|
}
|
||||||
if (sig == NULL)
|
if (sig == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -3772,6 +3774,67 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
|
||||||
Py_DECREF(kwonly_sig);
|
Py_DECREF(kwonly_sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
positional_only_passed_as_keyword(PyCodeObject *co, Py_ssize_t kwcount,
|
||||||
|
PyObject* const* kwnames)
|
||||||
|
{
|
||||||
|
int posonly_conflicts = 0;
|
||||||
|
PyObject* posonly_names = PyList_New(0);
|
||||||
|
|
||||||
|
for(int k=0; k < co->co_posonlyargcount; k++){
|
||||||
|
PyObject* posonly_name = PyTuple_GET_ITEM(co->co_varnames, k);
|
||||||
|
|
||||||
|
for (int k2=0; k2<kwcount; k2++){
|
||||||
|
/* Compare the pointers first and fallback to PyObject_RichCompareBool*/
|
||||||
|
PyObject* kwname = kwnames[k2];
|
||||||
|
if (kwname == posonly_name){
|
||||||
|
if(PyList_Append(posonly_names, kwname) != 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
posonly_conflicts++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmp = PyObject_RichCompareBool(posonly_name, kwname, Py_EQ);
|
||||||
|
|
||||||
|
if ( cmp > 0) {
|
||||||
|
if(PyList_Append(posonly_names, kwname) != 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
posonly_conflicts++;
|
||||||
|
} else if (cmp < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (posonly_conflicts) {
|
||||||
|
PyObject* comma = PyUnicode_FromString(", ");
|
||||||
|
if (comma == NULL) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
PyObject* error_names = PyUnicode_Join(comma, posonly_names);
|
||||||
|
Py_DECREF(comma);
|
||||||
|
if (error_names == NULL) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"%U() got some positional-only arguments passed"
|
||||||
|
" as keyword arguments: '%U'",
|
||||||
|
co->co_name, error_names);
|
||||||
|
Py_DECREF(error_names);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_DECREF(posonly_names);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
Py_XDECREF(posonly_names);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* This is gonna seem *real weird*, but if you put some other code between
|
/* This is gonna seem *real weird*, but if you put some other code between
|
||||||
PyEval_EvalFrame() and _PyEval_EvalFrameDefault() you will need to adjust
|
PyEval_EvalFrame() and _PyEval_EvalFrameDefault() you will need to adjust
|
||||||
the test in the if statements in Misc/gdbinit (pystack and pystackv). */
|
the test in the if statements in Misc/gdbinit (pystack and pystackv). */
|
||||||
|
@ -3791,8 +3854,8 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
PyObject **fastlocals, **freevars;
|
PyObject **fastlocals, **freevars;
|
||||||
PyThreadState *tstate;
|
PyThreadState *tstate;
|
||||||
PyObject *x, *u;
|
PyObject *x, *u;
|
||||||
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
|
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount + co->co_posonlyargcount;
|
||||||
Py_ssize_t i, n;
|
Py_ssize_t i, j, n;
|
||||||
PyObject *kwdict;
|
PyObject *kwdict;
|
||||||
|
|
||||||
if (globals == NULL) {
|
if (globals == NULL) {
|
||||||
|
@ -3826,14 +3889,28 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
kwdict = NULL;
|
kwdict = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy positional arguments into local variables */
|
/* Copy positional only arguments into local variables */
|
||||||
if (argcount > co->co_argcount) {
|
if (argcount > co->co_argcount + co->co_posonlyargcount) {
|
||||||
n = co->co_argcount;
|
n = co->co_posonlyargcount;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
n = argcount;
|
n = argcount;
|
||||||
}
|
}
|
||||||
for (i = 0; i < n; i++) {
|
for (j = 0; j < n; j++) {
|
||||||
|
x = args[j];
|
||||||
|
Py_INCREF(x);
|
||||||
|
SETLOCAL(j, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Copy positional arguments into local variables */
|
||||||
|
if (argcount > co->co_argcount + co->co_posonlyargcount) {
|
||||||
|
n += co->co_argcount;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
n = argcount;
|
||||||
|
}
|
||||||
|
for (i = j; i < n; i++) {
|
||||||
x = args[i];
|
x = args[i];
|
||||||
Py_INCREF(x);
|
Py_INCREF(x);
|
||||||
SETLOCAL(i, x);
|
SETLOCAL(i, x);
|
||||||
|
@ -3866,7 +3943,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
/* Speed hack: do raw pointer compares. As names are
|
/* Speed hack: do raw pointer compares. As names are
|
||||||
normally interned this should almost always hit. */
|
normally interned this should almost always hit. */
|
||||||
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
|
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
|
||||||
for (j = 0; j < total_args; j++) {
|
for (j = co->co_posonlyargcount; j < total_args; j++) {
|
||||||
PyObject *name = co_varnames[j];
|
PyObject *name = co_varnames[j];
|
||||||
if (name == keyword) {
|
if (name == keyword) {
|
||||||
goto kw_found;
|
goto kw_found;
|
||||||
|
@ -3874,7 +3951,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Slow fallback, just in case */
|
/* Slow fallback, just in case */
|
||||||
for (j = 0; j < total_args; j++) {
|
for (j = co->co_posonlyargcount; j < total_args; j++) {
|
||||||
PyObject *name = co_varnames[j];
|
PyObject *name = co_varnames[j];
|
||||||
int cmp = PyObject_RichCompareBool( keyword, name, Py_EQ);
|
int cmp = PyObject_RichCompareBool( keyword, name, Py_EQ);
|
||||||
if (cmp > 0) {
|
if (cmp > 0) {
|
||||||
|
@ -3887,6 +3964,11 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
|
|
||||||
assert(j >= total_args);
|
assert(j >= total_args);
|
||||||
if (kwdict == NULL) {
|
if (kwdict == NULL) {
|
||||||
|
|
||||||
|
if (co->co_posonlyargcount && positional_only_passed_as_keyword(co, kwcount, kwnames)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%U() got an unexpected keyword argument '%S'",
|
"%U() got an unexpected keyword argument '%S'",
|
||||||
co->co_name, keyword);
|
co->co_name, keyword);
|
||||||
|
@ -3910,14 +3992,14 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the number of positional arguments */
|
/* Check the number of positional arguments */
|
||||||
if (argcount > co->co_argcount && !(co->co_flags & CO_VARARGS)) {
|
if ((argcount > co->co_argcount + co->co_posonlyargcount) && !(co->co_flags & CO_VARARGS)) {
|
||||||
too_many_positional(co, argcount, defcount, fastlocals);
|
too_many_positional(co, argcount, defcount, fastlocals);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add missing positional arguments (copy default values from defs) */
|
/* Add missing positional arguments (copy default values from defs) */
|
||||||
if (argcount < co->co_argcount) {
|
if (argcount < co->co_posonlyargcount + co->co_argcount) {
|
||||||
Py_ssize_t m = co->co_argcount - defcount;
|
Py_ssize_t m = co->co_posonlyargcount + co->co_argcount - defcount;
|
||||||
Py_ssize_t missing = 0;
|
Py_ssize_t missing = 0;
|
||||||
for (i = argcount; i < m; i++) {
|
for (i = argcount; i < m; i++) {
|
||||||
if (GETLOCAL(i) == NULL) {
|
if (GETLOCAL(i) == NULL) {
|
||||||
|
@ -3944,7 +4026,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
/* Add missing keyword arguments (copy default values from kwdefs) */
|
/* Add missing keyword arguments (copy default values from kwdefs) */
|
||||||
if (co->co_kwonlyargcount > 0) {
|
if (co->co_kwonlyargcount > 0) {
|
||||||
Py_ssize_t missing = 0;
|
Py_ssize_t missing = 0;
|
||||||
for (i = co->co_argcount; i < total_args; i++) {
|
for (i = co->co_posonlyargcount + co->co_argcount; i < total_args; i++) {
|
||||||
PyObject *name;
|
PyObject *name;
|
||||||
if (GETLOCAL(i) != NULL)
|
if (GETLOCAL(i) != NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -122,6 +122,7 @@ struct compiler_unit {
|
||||||
PyObject *u_private; /* for private name mangling */
|
PyObject *u_private; /* for private name mangling */
|
||||||
|
|
||||||
Py_ssize_t u_argcount; /* number of arguments for block */
|
Py_ssize_t u_argcount; /* number of arguments for block */
|
||||||
|
Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */
|
||||||
Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */
|
Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */
|
||||||
/* Pointer to the most recently allocated block. By following b_list
|
/* Pointer to the most recently allocated block. By following b_list
|
||||||
members, you can reach all early allocated blocks. */
|
members, you can reach all early allocated blocks. */
|
||||||
|
@ -552,6 +553,7 @@ compiler_enter_scope(struct compiler *c, identifier name,
|
||||||
memset(u, 0, sizeof(struct compiler_unit));
|
memset(u, 0, sizeof(struct compiler_unit));
|
||||||
u->u_scope_type = scope_type;
|
u->u_scope_type = scope_type;
|
||||||
u->u_argcount = 0;
|
u->u_argcount = 0;
|
||||||
|
u->u_posonlyargcount = 0;
|
||||||
u->u_kwonlyargcount = 0;
|
u->u_kwonlyargcount = 0;
|
||||||
u->u_ste = PySymtable_Lookup(c->c_st, key);
|
u->u_ste = PySymtable_Lookup(c->c_st, key);
|
||||||
if (!u->u_ste) {
|
if (!u->u_ste) {
|
||||||
|
@ -2127,6 +2129,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
|
||||||
}
|
}
|
||||||
|
|
||||||
c->u->u_argcount = asdl_seq_LEN(args->args);
|
c->u->u_argcount = asdl_seq_LEN(args->args);
|
||||||
|
c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
|
||||||
c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
|
c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
|
||||||
VISIT_SEQ_IN_SCOPE(c, stmt, body);
|
VISIT_SEQ_IN_SCOPE(c, stmt, body);
|
||||||
co = assemble(c, 1);
|
co = assemble(c, 1);
|
||||||
|
@ -2507,6 +2510,7 @@ compiler_lambda(struct compiler *c, expr_ty e)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
c->u->u_argcount = asdl_seq_LEN(args->args);
|
c->u->u_argcount = asdl_seq_LEN(args->args);
|
||||||
|
c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
|
||||||
c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
|
c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
|
||||||
VISIT_IN_SCOPE(c, expr, e->v.Lambda.body);
|
VISIT_IN_SCOPE(c, expr, e->v.Lambda.body);
|
||||||
if (c->u->u_ste->ste_generator) {
|
if (c->u->u_ste->ste_generator) {
|
||||||
|
@ -5742,7 +5746,7 @@ makecode(struct compiler *c, struct assembler *a)
|
||||||
Py_ssize_t nlocals;
|
Py_ssize_t nlocals;
|
||||||
int nlocals_int;
|
int nlocals_int;
|
||||||
int flags;
|
int flags;
|
||||||
int argcount, kwonlyargcount, maxdepth;
|
int argcount, posonlyargcount, kwonlyargcount, maxdepth;
|
||||||
|
|
||||||
consts = consts_dict_keys_inorder(c->u->u_consts);
|
consts = consts_dict_keys_inorder(c->u->u_consts);
|
||||||
names = dict_keys_inorder(c->u->u_names, 0);
|
names = dict_keys_inorder(c->u->u_names, 0);
|
||||||
|
@ -5787,12 +5791,13 @@ makecode(struct compiler *c, struct assembler *a)
|
||||||
}
|
}
|
||||||
|
|
||||||
argcount = Py_SAFE_DOWNCAST(c->u->u_argcount, Py_ssize_t, int);
|
argcount = Py_SAFE_DOWNCAST(c->u->u_argcount, Py_ssize_t, int);
|
||||||
|
posonlyargcount = Py_SAFE_DOWNCAST(c->u->u_posonlyargcount, Py_ssize_t, int);
|
||||||
kwonlyargcount = Py_SAFE_DOWNCAST(c->u->u_kwonlyargcount, Py_ssize_t, int);
|
kwonlyargcount = Py_SAFE_DOWNCAST(c->u->u_kwonlyargcount, Py_ssize_t, int);
|
||||||
maxdepth = stackdepth(c);
|
maxdepth = stackdepth(c);
|
||||||
if (maxdepth < 0) {
|
if (maxdepth < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
co = PyCode_New(argcount, kwonlyargcount,
|
co = PyCode_New(argcount, posonlyargcount, kwonlyargcount,
|
||||||
nlocals_int, maxdepth, flags,
|
nlocals_int, maxdepth, flags,
|
||||||
bytecode, consts, names, varnames,
|
bytecode, consts, names, varnames,
|
||||||
freevars, cellvars,
|
freevars, cellvars,
|
||||||
|
|
|
@ -15,15 +15,15 @@
|
||||||
the appropriate bytes from M___main__.c. */
|
the appropriate bytes from M___main__.c. */
|
||||||
|
|
||||||
static unsigned char M___hello__[] = {
|
static unsigned char M___hello__[] = {
|
||||||
227,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,
|
227,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
0,64,0,0,0,115,16,0,0,0,100,0,90,0,101,1,
|
0,2,0,0,0,64,0,0,0,115,16,0,0,0,100,0,
|
||||||
100,1,131,1,1,0,100,2,83,0,41,3,84,122,12,72,
|
90,0,101,1,100,1,131,1,1,0,100,2,83,0,41,3,
|
||||||
101,108,108,111,32,119,111,114,108,100,33,78,41,2,218,11,
|
84,122,12,72,101,108,108,111,32,119,111,114,108,100,33,78,
|
||||||
105,110,105,116,105,97,108,105,122,101,100,218,5,112,114,105,
|
41,2,218,11,105,110,105,116,105,97,108,105,122,101,100,218,
|
||||||
110,116,169,0,114,3,0,0,0,114,3,0,0,0,250,22,
|
5,112,114,105,110,116,169,0,114,3,0,0,0,114,3,0,
|
||||||
46,47,84,111,111,108,115,47,102,114,101,101,122,101,47,102,
|
0,0,250,20,84,111,111,108,115,47,102,114,101,101,122,101,
|
||||||
108,97,103,46,112,121,218,8,60,109,111,100,117,108,101,62,
|
47,102,108,97,103,46,112,121,218,8,60,109,111,100,117,108,
|
||||||
1,0,0,0,115,2,0,0,0,4,1,
|
101,62,1,0,0,0,115,2,0,0,0,4,1,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SIZE (int)sizeof(M___hello__)
|
#define SIZE (int)sizeof(M___hello__)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -530,6 +530,7 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
|
||||||
PyCodeObject *co = (PyCodeObject *)v;
|
PyCodeObject *co = (PyCodeObject *)v;
|
||||||
W_TYPE(TYPE_CODE, p);
|
W_TYPE(TYPE_CODE, p);
|
||||||
w_long(co->co_argcount, p);
|
w_long(co->co_argcount, p);
|
||||||
|
w_long(co->co_posonlyargcount, p);
|
||||||
w_long(co->co_kwonlyargcount, p);
|
w_long(co->co_kwonlyargcount, p);
|
||||||
w_long(co->co_nlocals, p);
|
w_long(co->co_nlocals, p);
|
||||||
w_long(co->co_stacksize, p);
|
w_long(co->co_stacksize, p);
|
||||||
|
@ -1322,6 +1323,7 @@ r_object(RFILE *p)
|
||||||
case TYPE_CODE:
|
case TYPE_CODE:
|
||||||
{
|
{
|
||||||
int argcount;
|
int argcount;
|
||||||
|
int posonlyargcount;
|
||||||
int kwonlyargcount;
|
int kwonlyargcount;
|
||||||
int nlocals;
|
int nlocals;
|
||||||
int stacksize;
|
int stacksize;
|
||||||
|
@ -1347,6 +1349,10 @@ r_object(RFILE *p)
|
||||||
argcount = (int)r_long(p);
|
argcount = (int)r_long(p);
|
||||||
if (PyErr_Occurred())
|
if (PyErr_Occurred())
|
||||||
goto code_error;
|
goto code_error;
|
||||||
|
posonlyargcount = (int)r_long(p);
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
goto code_error;
|
||||||
|
}
|
||||||
kwonlyargcount = (int)r_long(p);
|
kwonlyargcount = (int)r_long(p);
|
||||||
if (PyErr_Occurred())
|
if (PyErr_Occurred())
|
||||||
goto code_error;
|
goto code_error;
|
||||||
|
@ -1391,7 +1397,7 @@ r_object(RFILE *p)
|
||||||
goto code_error;
|
goto code_error;
|
||||||
|
|
||||||
v = (PyObject *) PyCode_New(
|
v = (PyObject *) PyCode_New(
|
||||||
argcount, kwonlyargcount,
|
argcount, posonlyargcount, kwonlyargcount,
|
||||||
nlocals, stacksize, flags,
|
nlocals, stacksize, flags,
|
||||||
code, consts, names, varnames,
|
code, consts, names, varnames,
|
||||||
freevars, cellvars, filename, name,
|
freevars, cellvars, filename, name,
|
||||||
|
|
|
@ -1653,6 +1653,8 @@ symtable_visit_arguments(struct symtable *st, arguments_ty a)
|
||||||
/* skip default arguments inside function block
|
/* skip default arguments inside function block
|
||||||
XXX should ast be different?
|
XXX should ast be different?
|
||||||
*/
|
*/
|
||||||
|
if (a->posonlyargs && !symtable_visit_params(st, a->posonlyargs))
|
||||||
|
return 0;
|
||||||
if (a->args && !symtable_visit_params(st, a->args))
|
if (a->args && !symtable_visit_params(st, a->args))
|
||||||
return 0;
|
return 0;
|
||||||
if (a->kwonlyargs && !symtable_visit_params(st, a->kwonlyargs))
|
if (a->kwonlyargs && !symtable_visit_params(st, a->kwonlyargs))
|
||||||
|
|
|
@ -592,14 +592,18 @@ class Unparser:
|
||||||
def _arguments(self, t):
|
def _arguments(self, t):
|
||||||
first = True
|
first = True
|
||||||
# normal arguments
|
# normal arguments
|
||||||
defaults = [None] * (len(t.args) - len(t.defaults)) + t.defaults
|
all_args = t.posonlyargs + t.args
|
||||||
for a, d in zip(t.args, defaults):
|
defaults = [None] * (len(all_args) - len(t.defaults)) + t.defaults
|
||||||
|
for index, elements in enumerate(zip(all_args, defaults), 1):
|
||||||
|
a, d = elements
|
||||||
if first:first = False
|
if first:first = False
|
||||||
else: self.write(", ")
|
else: self.write(", ")
|
||||||
self.dispatch(a)
|
self.dispatch(a)
|
||||||
if d:
|
if d:
|
||||||
self.write("=")
|
self.write("=")
|
||||||
self.dispatch(d)
|
self.dispatch(d)
|
||||||
|
if index == len(t.posonlyargs):
|
||||||
|
self.write(", /")
|
||||||
|
|
||||||
# varargs, or bare '*' if no varargs but keyword-only arguments present
|
# varargs, or bare '*' if no varargs but keyword-only arguments present
|
||||||
if t.vararg or t.kwonlyargs:
|
if t.vararg or t.kwonlyargs:
|
||||||
|
|
Loading…
Reference in New Issue