mirror of
https://github.com/python/cpython
synced 2024-07-20 07:23:56 +00:00
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
|
||||
|
||||
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] (',' [TYPE_COMMENT] tfpdef ['=' test])* (TYPE_COMMENT | [',' [TYPE_COMMENT] ['**' tfpdef [','] [TYPE_COMMENT]]])
|
||||
| '**' tfpdef [','] [TYPE_COMMENT])
|
||||
)
|
||||
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] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
||||
|
|
10
Include/Python-ast.h
generated
10
Include/Python-ast.h
generated
|
@ -427,6 +427,7 @@ struct _excepthandler {
|
|||
|
||||
struct _arguments {
|
||||
asdl_seq *args;
|
||||
asdl_seq *posonlyargs;
|
||||
arg_ty vararg;
|
||||
asdl_seq *kwonlyargs;
|
||||
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
|
||||
end_lineno, int end_col_offset, PyArena
|
||||
*arena);
|
||||
#define arguments(a0, a1, a2, a3, a4, a5, a6) _Py_arguments(a0, a1, a2, a3, a4, a5, a6)
|
||||
arguments_ty _Py_arguments(asdl_seq * args, arg_ty vararg, asdl_seq *
|
||||
kwonlyargs, asdl_seq * kw_defaults, arg_ty kwarg,
|
||||
asdl_seq * defaults, PyArena *arena);
|
||||
#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, asdl_seq * posonlyargs, arg_ty
|
||||
vararg, asdl_seq * kwonlyargs, asdl_seq *
|
||||
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)
|
||||
arg_ty _Py_arg(identifier arg, expr_ty annotation, string type_comment, int
|
||||
lineno, int col_offset, int end_lineno, int end_col_offset,
|
||||
|
|
|
@ -21,6 +21,7 @@ typedef uint16_t _Py_CODEUNIT;
|
|||
typedef struct {
|
||||
PyObject_HEAD
|
||||
int co_argcount; /* #arguments, except *args */
|
||||
int co_posonlyargcount; /* #positional only arguments */
|
||||
int co_kwonlyargcount; /* #keyword only arguments */
|
||||
int co_nlocals; /* #local variables */
|
||||
int co_stacksize; /* #entries needed for evaluation stack */
|
||||
|
@ -102,7 +103,7 @@ PyAPI_DATA(PyTypeObject) PyCode_Type;
|
|||
|
||||
/* Public interface */
|
||||
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 *, int, PyObject *);
|
||||
/* same as struct above */
|
||||
|
|
|
@ -80,9 +80,9 @@ class struct_frozen(Structure):
|
|||
continue
|
||||
items.append((entry.name.decode("ascii"), entry.size))
|
||||
|
||||
expected = [("__hello__", 139),
|
||||
("__phello__", -139),
|
||||
("__phello__.spam", 139),
|
||||
expected = [("__hello__", 141),
|
||||
("__phello__", -141),
|
||||
("__phello__.spam", 141),
|
||||
]
|
||||
self.assertEqual(items, expected, "PyImport_FrozenModules example "
|
||||
"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("Filename: %s" % co.co_filename)
|
||||
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("Number of locals: %s" % co.co_nlocals)
|
||||
lines.append("Stack size: %s" % co.co_stacksize)
|
||||
|
|
|
@ -265,6 +265,7 @@ def _write_atomic(path, data, mode=0o666):
|
|||
# this might affected the first line number #32911)
|
||||
# Python 3.8a1 3400 (move frame block handling to compiler #17611)
|
||||
# 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
|
||||
# longer be understood by older implementations of the eval loop (usually
|
||||
|
@ -273,7 +274,7 @@ def _write_atomic(path, data, mode=0o666):
|
|||
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
|
||||
# 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
|
||||
|
||||
_PYCACHE = '__pycache__'
|
||||
|
|
|
@ -272,6 +272,7 @@ def iscode(object):
|
|||
| 16=nested | 32=generator | 64=nofree | 128=coroutine
|
||||
| 256=iterable_coroutine | 512=async_generator
|
||||
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_lnotab encoded mapping of line numbers to bytecode indices
|
||||
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
|
||||
appended. 'varargs' and 'varkw' are the names of the * and **
|
||||
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):
|
||||
raise TypeError('{!r} is not a code object'.format(co))
|
||||
|
||||
nargs = co.co_argcount
|
||||
names = co.co_varnames
|
||||
nargs = co.co_argcount
|
||||
nposonlyargs = co.co_posonlyargcount
|
||||
nkwargs = co.co_kwonlyargcount
|
||||
args = list(names[:nargs])
|
||||
kwonlyargs = list(names[nargs:nargs+nkwargs])
|
||||
nposargs = nargs + nposonlyargs
|
||||
posonlyargs = list(names[:nposonlyargs])
|
||||
args = list(names[nposonlyargs:nposonlyargs+nargs])
|
||||
kwonlyargs = list(names[nposargs:nposargs+nkwargs])
|
||||
step = 0
|
||||
|
||||
nargs += nposonlyargs
|
||||
nargs += nkwargs
|
||||
varargs = None
|
||||
if co.co_flags & CO_VARARGS:
|
||||
|
@ -1059,8 +1054,7 @@ def _getfullargs(co):
|
|||
varkw = None
|
||||
if co.co_flags & CO_VARKEYWORDS:
|
||||
varkw = co.co_varnames[nargs]
|
||||
return args, varargs, kwonlyargs, varkw
|
||||
|
||||
return Arguments(posonlyargs + args + kwonlyargs, varargs, varkw)
|
||||
|
||||
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
|
||||
|
||||
|
@ -1087,15 +1081,16 @@ def getargspec(func):
|
|||
warnings.warn("inspect.getargspec() is deprecated since Python 3.0, "
|
||||
"use inspect.signature() or inspect.getfullargspec()",
|
||||
DeprecationWarning, stacklevel=2)
|
||||
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
|
||||
getfullargspec(func)
|
||||
if kwonlyargs or ann:
|
||||
raise ValueError("Function has keyword-only parameters or annotations"
|
||||
", use getfullargspec() API which can support them")
|
||||
args, varargs, varkw, defaults, posonlyargs, kwonlyargs, \
|
||||
kwonlydefaults, ann = getfullargspec(func)
|
||||
if posonlyargs or kwonlyargs or ann:
|
||||
raise ValueError("Function has positional-only, keyword-only parameters"
|
||||
" or annotations, use getfullargspec() API which can"
|
||||
" support them")
|
||||
return ArgSpec(args, varargs, varkw, defaults)
|
||||
|
||||
FullArgSpec = namedtuple('FullArgSpec',
|
||||
'args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations')
|
||||
'args, varargs, varkw, defaults, posonlyargs, kwonlyargs, kwonlydefaults, annotations')
|
||||
|
||||
def getfullargspec(func):
|
||||
"""Get the names and default values of a callable object's parameters.
|
||||
|
@ -1145,6 +1140,7 @@ def getfullargspec(func):
|
|||
args = []
|
||||
varargs = None
|
||||
varkw = None
|
||||
posonlyargs = []
|
||||
kwonlyargs = []
|
||||
defaults = ()
|
||||
annotations = {}
|
||||
|
@ -1159,7 +1155,9 @@ def getfullargspec(func):
|
|||
name = param.name
|
||||
|
||||
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:
|
||||
args.append(name)
|
||||
if param.default is not param.empty:
|
||||
|
@ -1185,7 +1183,7 @@ def getfullargspec(func):
|
|||
defaults = None
|
||||
|
||||
return FullArgSpec(args, varargs, varkw, defaults,
|
||||
kwonlyargs, kwdefaults, annotations)
|
||||
posonlyargs, kwonlyargs, kwdefaults, annotations)
|
||||
|
||||
|
||||
ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')
|
||||
|
@ -1216,7 +1214,8 @@ def _formatannotation(annotation):
|
|||
return _formatannotation
|
||||
|
||||
def formatargspec(args, varargs=None, varkw=None, defaults=None,
|
||||
kwonlyargs=(), kwonlydefaults={}, annotations={},
|
||||
posonlyargs=(), kwonlyargs=(), kwonlydefaults={},
|
||||
annotations={},
|
||||
formatarg=str,
|
||||
formatvarargs=lambda name: '*' + name,
|
||||
formatvarkw=lambda name: '**' + name,
|
||||
|
@ -1249,12 +1248,17 @@ def formatargandannotation(arg):
|
|||
return result
|
||||
specs = []
|
||||
if defaults:
|
||||
firstdefault = len(args) - len(defaults)
|
||||
for i, arg in enumerate(args):
|
||||
firstdefault = len(posonlyargs) + len(args) - len(defaults)
|
||||
posonly_left = len(posonlyargs)
|
||||
for i, arg in enumerate([*posonlyargs, *args]):
|
||||
spec = formatargandannotation(arg)
|
||||
if defaults and i >= firstdefault:
|
||||
spec = spec + formatvalue(defaults[i - firstdefault])
|
||||
specs.append(spec)
|
||||
posonly_left -= 1
|
||||
if posonlyargs and posonly_left == 0:
|
||||
specs.append('/')
|
||||
|
||||
if varargs is not None:
|
||||
specs.append(formatvarargs(formatargandannotation(varargs)))
|
||||
else:
|
||||
|
@ -1342,7 +1346,8 @@ def getcallargs(*func_and_positional, **named):
|
|||
func = func_and_positional[0]
|
||||
positional = func_and_positional[1:]
|
||||
spec = getfullargspec(func)
|
||||
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = spec
|
||||
(args, varargs, varkw, defaults, posonlyargs,
|
||||
kwonlyargs, kwonlydefaults, ann) = spec
|
||||
f_name = func.__name__
|
||||
arg2value = {}
|
||||
|
||||
|
@ -1351,12 +1356,16 @@ def getcallargs(*func_and_positional, **named):
|
|||
# implicit 'self' (or 'cls' for classmethods) argument
|
||||
positional = (func.__self__,) + positional
|
||||
num_pos = len(positional)
|
||||
num_posonlyargs = len(posonlyargs)
|
||||
num_args = len(args)
|
||||
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)
|
||||
for i in range(n):
|
||||
arg2value[args[i]] = positional[i]
|
||||
arg2value[args[i]] = positional[num_posonlyargs+i]
|
||||
if varargs:
|
||||
arg2value[varargs] = tuple(positional[n:])
|
||||
possible_kwargs = set(args + kwonlyargs)
|
||||
|
@ -2137,9 +2146,12 @@ def _signature_from_function(cls, func):
|
|||
func_code = func.__code__
|
||||
pos_count = func_code.co_argcount
|
||||
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 = arg_names[pos_count:(pos_count + keyword_only_count)]
|
||||
keyword_only = arg_names[positional_count:(positional_count + keyword_only_count)]
|
||||
annotations = func.__annotations__
|
||||
defaults = func.__defaults__
|
||||
kwdefaults = func.__kwdefaults__
|
||||
|
@ -2151,23 +2163,33 @@ def _signature_from_function(cls, func):
|
|||
|
||||
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_default_count = pos_count - pos_default_count
|
||||
for name in positional[:non_default_count]:
|
||||
for name in all_positional[:non_default_count]:
|
||||
kind = _POSITIONAL_ONLY if posonly_left else _POSITIONAL_OR_KEYWORD
|
||||
annotation = annotations.get(name, _empty)
|
||||
parameters.append(Parameter(name, annotation=annotation,
|
||||
kind=_POSITIONAL_OR_KEYWORD))
|
||||
kind=kind))
|
||||
if posonly_left:
|
||||
posonly_left -= 1
|
||||
|
||||
# ... 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)
|
||||
parameters.append(Parameter(name, annotation=annotation,
|
||||
kind=_POSITIONAL_OR_KEYWORD,
|
||||
kind=kind,
|
||||
default=defaults[offset]))
|
||||
if posonly_left:
|
||||
posonly_left -= 1
|
||||
|
||||
# *args
|
||||
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)
|
||||
parameters.append(Parameter(name, annotation=annotation,
|
||||
kind=_VAR_POSITIONAL))
|
||||
|
@ -2184,7 +2206,7 @@ def _signature_from_function(cls, func):
|
|||
default=default))
|
||||
# **kwargs
|
||||
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:
|
||||
index += 1
|
||||
|
||||
|
|
|
@ -619,8 +619,9 @@ def replace_paths_in_code(self, co):
|
|||
if isinstance(consts[i], type(co)):
|
||||
consts[i] = self.replace_paths_in_code(consts[i])
|
||||
|
||||
return types.CodeType(co.co_argcount, co.co_kwonlyargcount,
|
||||
co.co_nlocals, co.co_stacksize, co.co_flags,
|
||||
return types.CodeType(co.co_argcount, co.co_posonlyargcount,
|
||||
co.co_kwonlyargcount, co.co_nlocals,
|
||||
co.co_stacksize, co.co_flags,
|
||||
co.co_code, tuple(consts), co.co_names,
|
||||
co.co_varnames, new_filename, co.co_name,
|
||||
co.co_firstlineno, co.co_lnotab, co.co_freevars,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# line 5
|
||||
|
||||
# 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)
|
||||
|
||||
# line 11
|
||||
|
|
|
@ -137,3 +137,19 @@ def func136():
|
|||
def func137():
|
||||
never_reached1
|
||||
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 @@ def test_field_attr_existence(self):
|
|||
|
||||
def test_arguments(self):
|
||||
x = ast.arguments()
|
||||
self.assertEqual(x._fields, ('args', 'vararg', 'kwonlyargs',
|
||||
self.assertEqual(x._fields, ('args', 'posonlyargs', 'vararg', 'kwonlyargs',
|
||||
'kw_defaults', 'kwarg', 'defaults'))
|
||||
|
||||
with self.assertRaises(AttributeError):
|
||||
x.vararg
|
||||
|
||||
x = ast.arguments(*range(1, 7))
|
||||
self.assertEqual(x.vararg, 2)
|
||||
x = ast.arguments(*range(1, 8))
|
||||
self.assertEqual(x.vararg, 3)
|
||||
|
||||
def test_field_attr_writable(self):
|
||||
x = ast.Num()
|
||||
|
@ -816,22 +816,25 @@ def test_module(self):
|
|||
self.mod(m, "must have Load context", "eval")
|
||||
|
||||
def _check_arguments(self, fac, check):
|
||||
def arguments(args=None, vararg=None,
|
||||
def arguments(args=None, posonlyargs=None, vararg=None,
|
||||
kwonlyargs=None, kwarg=None,
|
||||
defaults=None, kw_defaults=None):
|
||||
if args is None:
|
||||
args = []
|
||||
if posonlyargs is None:
|
||||
posonlyargs = []
|
||||
if kwonlyargs is None:
|
||||
kwonlyargs = []
|
||||
if defaults is None:
|
||||
defaults = []
|
||||
if kw_defaults is None:
|
||||
kw_defaults = []
|
||||
args = ast.arguments(args, vararg, kwonlyargs, kw_defaults,
|
||||
kwarg, defaults)
|
||||
args = ast.arguments(args, posonlyargs, vararg, kwonlyargs,
|
||||
kw_defaults, kwarg, defaults)
|
||||
return fac(args)
|
||||
args = [ast.arg("x", ast.Name("x", ast.Store()))]
|
||||
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(defaults=[ast.Num(3)]),
|
||||
"more positional defaults than args")
|
||||
|
@ -847,7 +850,7 @@ def arguments(args=None, vararg=None,
|
|||
"must have Load context")
|
||||
|
||||
def test_funcdef(self):
|
||||
a = ast.arguments([], None, [], [], None, [])
|
||||
a = ast.arguments([], [], None, [], [], None, [])
|
||||
f = ast.FunctionDef("x", a, [], [], None)
|
||||
self.stmt(f, "empty body on FunctionDef")
|
||||
f = ast.FunctionDef("x", a, [ast.Pass()], [ast.Name("x", ast.Store())],
|
||||
|
@ -1013,7 +1016,7 @@ def test_unaryop(self):
|
|||
self.expr(u, "must have Load context")
|
||||
|
||||
def test_lambda(self):
|
||||
a = ast.arguments([], None, [], [], None, [])
|
||||
a = ast.arguments([], [], None, [], [], None, [])
|
||||
self.expr(ast.Lambda(a, ast.Name("x", ast.Store())),
|
||||
"must have Load context")
|
||||
def fac(args):
|
||||
|
@ -1636,17 +1639,17 @@ def main():
|
|||
exec_results = [
|
||||
('Module', [('Expr', (1, 0), ('Constant', (1, 0), None, 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, []), [('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, [('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', [], 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', [], [], 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', [('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, 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', [('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', [], [], [('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', [('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', [('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)], []),
|
||||
|
@ -1677,16 +1680,16 @@ def main():
|
|||
('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', ('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, []), [('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, []), [('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, []), [('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), ('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', [('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', (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', [('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', [('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)))], []),
|
||||
]
|
||||
single_results = [
|
||||
|
@ -1697,7 +1700,7 @@ def main():
|
|||
('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', ('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), [], [])),
|
||||
('Expression', ('Set', (1, 0), [('Constant', (1, 1), None, None)])),
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
>>> dump(f.__code__)
|
||||
name: f
|
||||
argcount: 1
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 0
|
||||
names: ()
|
||||
varnames: ('x', 'g')
|
||||
|
@ -21,6 +22,7 @@
|
|||
>>> dump(f(4).__code__)
|
||||
name: g
|
||||
argcount: 1
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 0
|
||||
names: ()
|
||||
varnames: ('y',)
|
||||
|
@ -40,6 +42,7 @@
|
|||
>>> dump(h.__code__)
|
||||
name: h
|
||||
argcount: 2
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 0
|
||||
names: ()
|
||||
varnames: ('x', 'y', 'a', 'b', 'c')
|
||||
|
@ -57,6 +60,7 @@
|
|||
>>> dump(attrs.__code__)
|
||||
name: attrs
|
||||
argcount: 1
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 0
|
||||
names: ('print', 'attr1', 'attr2', 'attr3')
|
||||
varnames: ('obj',)
|
||||
|
@ -75,6 +79,7 @@
|
|||
>>> dump(optimize_away.__code__)
|
||||
name: optimize_away
|
||||
argcount: 0
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 0
|
||||
names: ()
|
||||
varnames: ()
|
||||
|
@ -91,6 +96,7 @@
|
|||
>>> dump(keywordonly_args.__code__)
|
||||
name: keywordonly_args
|
||||
argcount: 2
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 1
|
||||
names: ()
|
||||
varnames: ('a', 'b', 'k1')
|
||||
|
@ -100,6 +106,23 @@
|
|||
flags: 67
|
||||
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
|
||||
|
@ -126,7 +149,8 @@ def consts(t):
|
|||
|
||||
def dump(co):
|
||||
"""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"]:
|
||||
print("%s: %s" % (attr, getattr(co, "co_" + attr)))
|
||||
print("consts:", tuple(consts(co.co_consts)))
|
||||
|
@ -157,7 +181,7 @@ def create_closure(__class__):
|
|||
def new_code(c):
|
||||
'''A new code object with a __class__ cell added to freevars'''
|
||||
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_varnames, c.co_filename, c.co_name, c.co_firstlineno,
|
||||
c.co_lnotab, c.co_freevars + ('__class__',), c.co_cellvars)
|
||||
|
|
|
@ -617,6 +617,7 @@ def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs):
|
|||
Name: code_info
|
||||
Filename: (.*)
|
||||
Argument count: 1
|
||||
Positional-only arguments: 0
|
||||
Kw-only arguments: 0
|
||||
Number of locals: 1
|
||||
Stack size: 3
|
||||
|
@ -631,50 +632,53 @@ def get_disassembly(self, func, lasti=-1, wrapper=True, **kwargs):
|
|||
if sys.flags.optimize < 2 else (None,))
|
||||
|
||||
@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):
|
||||
print(x, y, z, c, d, e, f)
|
||||
yield x, y, z, c, d, e, f
|
||||
print(a, b, x, y, z, c, d, e, f)
|
||||
yield a, b, x, y, z, c, d, e, f
|
||||
|
||||
code_info_tricky = """\
|
||||
Name: tricky
|
||||
Filename: (.*)
|
||||
Argument count: 3
|
||||
Positional-only arguments: 2
|
||||
Kw-only arguments: 3
|
||||
Number of locals: 8
|
||||
Stack size: 7
|
||||
Number of locals: 10
|
||||
Stack size: 9
|
||||
Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
|
||||
Constants:
|
||||
0: None
|
||||
1: <code object f at (.*), file "(.*)", line (.*)>
|
||||
2: 'tricky.<locals>.f'
|
||||
Variable names:
|
||||
0: x
|
||||
1: y
|
||||
2: z
|
||||
3: c
|
||||
4: d
|
||||
5: e
|
||||
6: args
|
||||
7: kwds
|
||||
0: a
|
||||
1: b
|
||||
2: x
|
||||
3: y
|
||||
4: z
|
||||
5: c
|
||||
6: d
|
||||
7: e
|
||||
8: args
|
||||
9: kwds
|
||||
Cell variables:
|
||||
0: [edfxyz]
|
||||
1: [edfxyz]
|
||||
2: [edfxyz]
|
||||
3: [edfxyz]
|
||||
4: [edfxyz]
|
||||
5: [edfxyz]"""
|
||||
0: [abedfxyz]
|
||||
1: [abedfxyz]
|
||||
2: [abedfxyz]
|
||||
3: [abedfxyz]
|
||||
4: [abedfxyz]
|
||||
5: [abedfxyz]"""
|
||||
# NOTE: the order of the cell variables above depends on dictionary order!
|
||||
|
||||
co_tricky_nested_f = tricky.__func__.__code__.co_consts[1]
|
||||
|
||||
code_info_tricky_nested_f = """\
|
||||
Name: f
|
||||
Filename: (.*)
|
||||
Argument count: 1
|
||||
Positional-only arguments: 0
|
||||
Kw-only arguments: 0
|
||||
Number of locals: 1
|
||||
Stack size: 8
|
||||
Stack size: 10
|
||||
Flags: OPTIMIZED, NEWLOCALS, NESTED
|
||||
Constants:
|
||||
0: None
|
||||
|
@ -683,17 +687,18 @@ def f(c=c):
|
|||
Variable names:
|
||||
0: c
|
||||
Free variables:
|
||||
0: [edfxyz]
|
||||
1: [edfxyz]
|
||||
2: [edfxyz]
|
||||
3: [edfxyz]
|
||||
4: [edfxyz]
|
||||
5: [edfxyz]"""
|
||||
0: [abedfxyz]
|
||||
1: [abedfxyz]
|
||||
2: [abedfxyz]
|
||||
3: [abedfxyz]
|
||||
4: [abedfxyz]
|
||||
5: [abedfxyz]"""
|
||||
|
||||
code_info_expr_str = """\
|
||||
Name: <module>
|
||||
Filename: <disassembly>
|
||||
Argument count: 0
|
||||
Positional-only arguments: 0
|
||||
Kw-only arguments: 0
|
||||
Number of locals: 0
|
||||
Stack size: 2
|
||||
|
@ -707,6 +712,7 @@ def f(c=c):
|
|||
Name: <module>
|
||||
Filename: <disassembly>
|
||||
Argument count: 0
|
||||
Positional-only arguments: 0
|
||||
Kw-only arguments: 0
|
||||
Number of locals: 0
|
||||
Stack size: 2
|
||||
|
@ -721,6 +727,7 @@ def f(c=c):
|
|||
Name: <module>
|
||||
Filename: <disassembly>
|
||||
Argument count: 0
|
||||
Positional-only arguments: 0
|
||||
Kw-only arguments: 0
|
||||
Number of locals: 0
|
||||
Stack size: 2
|
||||
|
@ -742,6 +749,7 @@ async def async_def():
|
|||
Name: async_def
|
||||
Filename: (.*)
|
||||
Argument count: 0
|
||||
Positional-only arguments: 0
|
||||
Kw-only arguments: 0
|
||||
Number of locals: 2
|
||||
Stack size: 10
|
||||
|
|
|
@ -581,6 +581,13 @@ def add(self, x, y):
|
|||
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))
|
||||
|
||||
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):
|
||||
|
||||
|
|
|
@ -674,7 +674,8 @@ def test_foreign_code(self):
|
|||
foreign_code = importlib.import_module.__code__
|
||||
pos = constants.index(1)
|
||||
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_flags, code.co_code, tuple(constants),
|
||||
code.co_names, code.co_varnames, code.co_filename,
|
||||
|
|
|
@ -862,7 +862,7 @@ def test_magic_number(self):
|
|||
in advance. Such exceptional releases will then require an
|
||||
adjustment to this test case.
|
||||
"""
|
||||
EXPECTED_MAGIC_NUMBER = 3400
|
||||
EXPECTED_MAGIC_NUMBER = 3410
|
||||
actual = int.from_bytes(importlib.util.MAGIC_NUMBER[:2], 'little')
|
||||
|
||||
msg = (
|
||||
|
|
|
@ -763,30 +763,31 @@ def assertArgSpecEquals(self, routine, args_e, varargs_e=None,
|
|||
|
||||
def assertFullArgSpecEquals(self, routine, args_e, varargs_e=None,
|
||||
varkw_e=None, defaults_e=None,
|
||||
kwonlyargs_e=[], kwonlydefaults_e=None,
|
||||
posonlyargs_e=[], kwonlyargs_e=[],
|
||||
kwonlydefaults_e=None,
|
||||
ann_e={}, formatted=None):
|
||||
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
|
||||
args, varargs, varkw, defaults, posonlyargs, kwonlyargs, kwonlydefaults, ann = \
|
||||
inspect.getfullargspec(routine)
|
||||
self.assertEqual(args, args_e)
|
||||
self.assertEqual(varargs, varargs_e)
|
||||
self.assertEqual(varkw, varkw_e)
|
||||
self.assertEqual(defaults, defaults_e)
|
||||
self.assertEqual(posonlyargs, posonlyargs_e)
|
||||
self.assertEqual(kwonlyargs, kwonlyargs_e)
|
||||
self.assertEqual(kwonlydefaults, kwonlydefaults_e)
|
||||
self.assertEqual(ann, ann_e)
|
||||
if formatted is not None:
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
self.assertEqual(inspect.formatargspec(args, varargs, varkw, defaults,
|
||||
kwonlyargs, kwonlydefaults, ann),
|
||||
posonlyargs, kwonlyargs,
|
||||
kwonlydefaults, ann),
|
||||
formatted)
|
||||
|
||||
def test_getargspec(self):
|
||||
self.assertArgSpecEquals(mod.eggs, ['x', 'y'], formatted='(x, y)')
|
||||
|
||||
self.assertArgSpecEquals(mod.spam,
|
||||
['a', 'b', 'c', 'd', 'e', 'f'],
|
||||
'g', 'h', (3, 4, 5),
|
||||
'(a, b, c, d=3, e=4, f=5, *g, **h)')
|
||||
self.assertRaises(ValueError, self.assertArgSpecEquals,
|
||||
mod.spam, [])
|
||||
|
||||
self.assertRaises(ValueError, self.assertArgSpecEquals,
|
||||
mod2.keyworded, [])
|
||||
|
@ -810,6 +811,26 @@ def test_getfullargspec(self):
|
|||
kwonlyargs_e=['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):
|
||||
# Issue 20684: low level introspection API must ignore __wrapped__
|
||||
@functools.wraps(mod.spam)
|
||||
|
@ -856,7 +877,7 @@ def test():
|
|||
spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY)
|
||||
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(a:'spam') -> 'ham': pass
|
||||
|
@ -870,11 +891,11 @@ def test(): pass
|
|||
@unittest.skipIf(MISSING_C_DOCSTRINGS,
|
||||
"Signature information for builtins requires docstrings")
|
||||
def test_getfullargspec_builtin_methods(self):
|
||||
self.assertFullArgSpecEquals(_pickle.Pickler.dump,
|
||||
args_e=['self', 'obj'], formatted='(self, obj)')
|
||||
self.assertFullArgSpecEquals(_pickle.Pickler.dump, [],
|
||||
posonlyargs_e=['self', 'obj'], formatted='(self, obj, /)')
|
||||
|
||||
self.assertFullArgSpecEquals(_pickle.Pickler(io.BytesIO()).dump,
|
||||
args_e=['self', 'obj'], formatted='(self, obj)')
|
||||
self.assertFullArgSpecEquals(_pickle.Pickler(io.BytesIO()).dump, [],
|
||||
posonlyargs_e=['self', 'obj'], formatted='(self, obj, /)')
|
||||
|
||||
self.assertFullArgSpecEquals(
|
||||
os.stat,
|
||||
|
|
|
@ -233,6 +233,18 @@ def test_function_defs(self):
|
|||
self.check_suite("def f(*args, a, b = 5): 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
|
||||
self.check_suite("def f(a: int): pass")
|
||||
self.check_suite("def f(a: int = 5): pass")
|
||||
|
|
403
Lib/test/test_positional_only_arg.py
Normal file
403
Lib/test/test_positional_only_arg.py
Normal file
|
@ -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()
|
|
@ -101,7 +101,7 @@ def fab(
|
|||
|
||||
def fab(
|
||||
a, # type: A
|
||||
b # type: B
|
||||
b # type: B
|
||||
):
|
||||
pass
|
||||
|
||||
|
|
|
@ -263,7 +263,7 @@ def coroutine(func):
|
|||
# TODO: Implement this in C.
|
||||
co = func.__code__
|
||||
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_flags | 0x100, # 0x100 == CO_ITERABLE_COROUTINE
|
||||
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))
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
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
|
||||
a default value: use default values as arguments .*/
|
||||
args = _PyTuple_ITEMS(argdefs);
|
||||
|
@ -406,11 +406,11 @@ _PyFunction_FastCallKeywords(PyObject *func, PyObject *const *stack,
|
|||
if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
|
||||
(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);
|
||||
}
|
||||
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
|
||||
a default value: use default values as arguments .*/
|
||||
stack = _PyTuple_ITEMS(argdefs);
|
||||
|
|
|
@ -96,7 +96,7 @@ intern_string_constants(PyObject *tuple)
|
|||
|
||||
|
||||
PyCodeObject *
|
||||
PyCode_New(int argcount, int kwonlyargcount,
|
||||
PyCode_New(int argcount, int posonlyargcount, int kwonlyargcount,
|
||||
int nlocals, int stacksize, int flags,
|
||||
PyObject *code, PyObject *consts, PyObject *names,
|
||||
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;
|
||||
|
||||
/* Check argument types */
|
||||
if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 ||
|
||||
code == NULL || !PyBytes_Check(code) ||
|
||||
if (argcount < 0 || posonlyargcount < 0 || kwonlyargcount < 0 ||
|
||||
nlocals < 0 || code == NULL || !PyBytes_Check(code) ||
|
||||
consts == NULL || !PyTuple_Check(consts) ||
|
||||
names == NULL || !PyTuple_Check(names) ||
|
||||
varnames == NULL || !PyTuple_Check(varnames) ||
|
||||
|
@ -141,10 +141,12 @@ PyCode_New(int argcount, int kwonlyargcount,
|
|||
}
|
||||
|
||||
n_varnames = PyTuple_GET_SIZE(varnames);
|
||||
if (argcount <= n_varnames && kwonlyargcount <= n_varnames) {
|
||||
if (posonlyargcount + argcount <= n_varnames
|
||||
&& kwonlyargcount <= n_varnames) {
|
||||
/* Never overflows. */
|
||||
total_args = (Py_ssize_t)argcount + (Py_ssize_t)kwonlyargcount +
|
||||
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
|
||||
total_args = (Py_ssize_t)posonlyargcount + (Py_ssize_t)argcount
|
||||
+ (Py_ssize_t)kwonlyargcount +
|
||||
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
|
||||
}
|
||||
else {
|
||||
total_args = n_varnames + 1;
|
||||
|
@ -193,6 +195,7 @@ PyCode_New(int argcount, int kwonlyargcount,
|
|||
return NULL;
|
||||
}
|
||||
co->co_argcount = argcount;
|
||||
co->co_posonlyargcount = posonlyargcount;
|
||||
co->co_kwonlyargcount = kwonlyargcount;
|
||||
co->co_nlocals = nlocals;
|
||||
co->co_stacksize = stacksize;
|
||||
|
@ -249,6 +252,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
|
|||
goto failed;
|
||||
|
||||
result = PyCode_New(0, /* argcount */
|
||||
0, /* posonlyargcount */
|
||||
0, /* kwonlyargcount */
|
||||
0, /* nlocals */
|
||||
0, /* stacksize */
|
||||
|
@ -274,21 +278,22 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
|
|||
#define OFF(x) offsetof(PyCodeObject, x)
|
||||
|
||||
static PyMemberDef code_memberlist[] = {
|
||||
{"co_argcount", T_INT, OFF(co_argcount), READONLY},
|
||||
{"co_kwonlyargcount", T_INT, OFF(co_kwonlyargcount), READONLY},
|
||||
{"co_nlocals", T_INT, OFF(co_nlocals), READONLY},
|
||||
{"co_stacksize",T_INT, OFF(co_stacksize), READONLY},
|
||||
{"co_flags", T_INT, OFF(co_flags), READONLY},
|
||||
{"co_code", T_OBJECT, OFF(co_code), READONLY},
|
||||
{"co_consts", T_OBJECT, OFF(co_consts), READONLY},
|
||||
{"co_names", T_OBJECT, OFF(co_names), READONLY},
|
||||
{"co_varnames", T_OBJECT, OFF(co_varnames), READONLY},
|
||||
{"co_freevars", T_OBJECT, OFF(co_freevars), READONLY},
|
||||
{"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY},
|
||||
{"co_filename", T_OBJECT, OFF(co_filename), READONLY},
|
||||
{"co_name", T_OBJECT, OFF(co_name), READONLY},
|
||||
{"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY},
|
||||
{"co_lnotab", T_OBJECT, OFF(co_lnotab), 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_nlocals", T_INT, OFF(co_nlocals), READONLY},
|
||||
{"co_stacksize",T_INT, OFF(co_stacksize), READONLY},
|
||||
{"co_flags", T_INT, OFF(co_flags), READONLY},
|
||||
{"co_code", T_OBJECT, OFF(co_code), READONLY},
|
||||
{"co_consts", T_OBJECT, OFF(co_consts), READONLY},
|
||||
{"co_names", T_OBJECT, OFF(co_names), READONLY},
|
||||
{"co_varnames", T_OBJECT, OFF(co_varnames), READONLY},
|
||||
{"co_freevars", T_OBJECT, OFF(co_freevars), READONLY},
|
||||
{"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY},
|
||||
{"co_filename", T_OBJECT, OFF(co_filename), READONLY},
|
||||
{"co_name", T_OBJECT, OFF(co_name), READONLY},
|
||||
{"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY},
|
||||
{"co_lnotab", T_OBJECT, OFF(co_lnotab), READONLY},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
@ -335,9 +340,9 @@ validate_and_copy_tuple(PyObject *tup)
|
|||
}
|
||||
|
||||
PyDoc_STRVAR(code_doc,
|
||||
"code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,\n\
|
||||
constants, names, varnames, filename, name, firstlineno,\n\
|
||||
lnotab[, freevars[, cellvars]])\n\
|
||||
"code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n\
|
||||
flags, codestring, constants, names, varnames, filename, name,\n\
|
||||
firstlineno, lnotab[, freevars[, cellvars]])\n\
|
||||
\n\
|
||||
Create a code object. Not for the faint of heart.");
|
||||
|
||||
|
@ -345,6 +350,7 @@ static PyObject *
|
|||
code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||
{
|
||||
int argcount;
|
||||
int posonlyargcount;
|
||||
int kwonlyargcount;
|
||||
int nlocals;
|
||||
int stacksize;
|
||||
|
@ -361,8 +367,8 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|||
int firstlineno;
|
||||
PyObject *lnotab;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iiiiiSO!O!O!UUiS|O!O!:code",
|
||||
&argcount, &kwonlyargcount,
|
||||
if (!PyArg_ParseTuple(args, "iiiiiiSO!O!O!UUiS|O!O!:code",
|
||||
&argcount, &posonlyargcount, &kwonlyargcount,
|
||||
&nlocals, &stacksize, &flags,
|
||||
&code,
|
||||
&PyTuple_Type, &consts,
|
||||
|
@ -381,6 +387,13 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (posonlyargcount < 0) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"code: posonlyargcount must not be negative");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (kwonlyargcount < 0) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
|
@ -413,7 +426,7 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|||
if (ourcellvars == NULL)
|
||||
goto cleanup;
|
||||
|
||||
co = (PyObject *)PyCode_New(argcount, kwonlyargcount,
|
||||
co = (PyObject *)PyCode_New(argcount, posonlyargcount, kwonlyargcount,
|
||||
nlocals, stacksize, flags,
|
||||
code, consts, ournames, ourvarnames,
|
||||
ourfreevars, ourcellvars, filename,
|
||||
|
@ -645,9 +658,11 @@ code_richcompare(PyObject *self, PyObject *other, int op)
|
|||
cp = (PyCodeObject *)other;
|
||||
|
||||
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;
|
||||
if (!eq) goto unequal;
|
||||
eq = co->co_posonlyargcount == cp->co_posonlyargcount;
|
||||
if (!eq) goto unequal;
|
||||
eq = co->co_kwonlyargcount == cp->co_kwonlyargcount;
|
||||
if (!eq) goto unequal;
|
||||
eq = co->co_nlocals == cp->co_nlocals;
|
||||
|
@ -720,7 +735,7 @@ code_hash(PyCodeObject *co)
|
|||
h6 = PyObject_Hash(co->co_cellvars);
|
||||
if (h6 == -1) return -1;
|
||||
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;
|
||||
if (h == -1) h = -2;
|
||||
return h;
|
||||
|
|
|
@ -1139,7 +1139,7 @@ static PYC_MAGIC magic_values[] = {
|
|||
{ 3320, 3351, L"3.5" },
|
||||
{ 3360, 3379, L"3.6" },
|
||||
{ 3390, 3399, L"3.7" },
|
||||
{ 3400, 3409, L"3.8" },
|
||||
{ 3400, 3410, L"3.8" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
|
|
@ -111,8 +111,8 @@ module Python
|
|||
excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body)
|
||||
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
||||
|
||||
arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults,
|
||||
arg? kwarg, expr* defaults)
|
||||
arguments = (arg* args, arg* posonlyargs, arg? vararg, arg* kwonlyargs,
|
||||
expr* kw_defaults, arg? kwarg, expr* defaults)
|
||||
|
||||
arg = (identifier arg, expr? annotation, string? type_comment)
|
||||
attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset)
|
||||
|
|
50
Python/Python-ast.c
generated
50
Python/Python-ast.c
generated
|
@ -469,6 +469,7 @@ static char *ExceptHandler_fields[]={
|
|||
};
|
||||
static PyTypeObject *arguments_type;
|
||||
static PyObject* ast2obj_arguments(void*);
|
||||
_Py_IDENTIFIER(posonlyargs);
|
||||
_Py_IDENTIFIER(vararg);
|
||||
_Py_IDENTIFIER(kwonlyargs);
|
||||
_Py_IDENTIFIER(kw_defaults);
|
||||
|
@ -476,6 +477,7 @@ _Py_IDENTIFIER(kwarg);
|
|||
_Py_IDENTIFIER(defaults);
|
||||
static char *arguments_fields[]={
|
||||
"args",
|
||||
"posonlyargs",
|
||||
"vararg",
|
||||
"kwonlyargs",
|
||||
"kw_defaults",
|
||||
|
@ -1141,7 +1143,7 @@ static int init_types(void)
|
|||
ExceptHandler_type = make_type("ExceptHandler", excepthandler_type,
|
||||
ExceptHandler_fields, 3);
|
||||
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 (!add_attributes(arguments_type, NULL, 0)) return 0;
|
||||
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(asdl_seq * args, arg_ty vararg, asdl_seq * kwonlyargs, asdl_seq *
|
||||
kw_defaults, arg_ty kwarg, asdl_seq * defaults, PyArena *arena)
|
||||
arguments(asdl_seq * args, asdl_seq * posonlyargs, arg_ty vararg, asdl_seq *
|
||||
kwonlyargs, asdl_seq * kw_defaults, arg_ty kwarg, asdl_seq *
|
||||
defaults, PyArena *arena)
|
||||
{
|
||||
arguments_ty p;
|
||||
p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p));
|
||||
if (!p)
|
||||
return NULL;
|
||||
p->args = args;
|
||||
p->posonlyargs = posonlyargs;
|
||||
p->vararg = vararg;
|
||||
p->kwonlyargs = kwonlyargs;
|
||||
p->kw_defaults = kw_defaults;
|
||||
|
@ -3954,6 +3958,11 @@ ast2obj_arguments(void* _o)
|
|||
if (_PyObject_SetAttrId(result, &PyId_args, value) == -1)
|
||||
goto failed;
|
||||
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);
|
||||
if (!value) goto failed;
|
||||
if (_PyObject_SetAttrId(result, &PyId_vararg, value) == -1)
|
||||
|
@ -8267,6 +8276,7 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
|
|||
{
|
||||
PyObject* tmp = NULL;
|
||||
asdl_seq* args;
|
||||
asdl_seq* posonlyargs;
|
||||
arg_ty vararg;
|
||||
asdl_seq* kwonlyargs;
|
||||
asdl_seq* kw_defaults;
|
||||
|
@ -8303,6 +8313,36 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
|
|||
}
|
||||
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) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -8419,8 +8459,8 @@ obj2ast_arguments(PyObject* obj, arguments_ty* out, PyArena* arena)
|
|||
}
|
||||
Py_CLEAR(tmp);
|
||||
}
|
||||
*out = arguments(args, vararg, kwonlyargs, kw_defaults, kwarg, defaults,
|
||||
arena);
|
||||
*out = arguments(args, posonlyargs, vararg, kwonlyargs, kw_defaults, kwarg,
|
||||
defaults, arena);
|
||||
return 0;
|
||||
failed:
|
||||
Py_XDECREF(tmp);
|
||||
|
|
100
Python/ast.c
100
Python/ast.c
|
@ -110,8 +110,9 @@ expr_context_name(expr_context_ty ctx)
|
|||
static int
|
||||
validate_arguments(arguments_ty args)
|
||||
{
|
||||
if (!validate_args(args->args))
|
||||
if (!validate_args(args->posonlyargs) || !validate_args(args->args)) {
|
||||
return 0;
|
||||
}
|
||||
if (args->vararg && args->vararg->annotation
|
||||
&& !validate_expr(args->vararg->annotation, Load)) {
|
||||
return 0;
|
||||
|
@ -1431,31 +1432,73 @@ ast_for_arguments(struct compiling *c, const node *n)
|
|||
and varargslist (lambda definition).
|
||||
|
||||
parameters: '(' [typedargslist] ')'
|
||||
typedargslist: (tfpdef ['=' test] (',' tfpdef ['=' test])* [',' [
|
||||
'*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]]
|
||||
| '**' tfpdef [',']]]
|
||||
| '*' [tfpdef] (',' tfpdef ['=' test])* [',' ['**' tfpdef [',']]]
|
||||
| '**' tfpdef [','])
|
||||
|
||||
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)"
|
||||
|
||||
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]
|
||||
varargslist: (vfpdef ['=' test] (',' vfpdef ['=' test])* [',' [
|
||||
'*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
||||
| '**' vfpdef [',']]]
|
||||
| '*' [vfpdef] (',' vfpdef ['=' test])* [',' ['**' vfpdef [',']]]
|
||||
| '**' vfpdef [',']
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
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;
|
||||
asdl_seq *posargs, *posdefaults, *kwonlyargs, *kwdefaults;
|
||||
asdl_seq *posonlyargs, *posargs, *posdefaults, *kwonlyargs, *kwdefaults;
|
||||
arg_ty vararg = NULL, kwarg = NULL;
|
||||
arg_ty arg = NULL;
|
||||
node *ch;
|
||||
|
||||
if (TYPE(n) == parameters) {
|
||||
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);
|
||||
}
|
||||
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) == vfpdef || TYPE(ch) == tfpdef) nposargs++;
|
||||
if (TYPE(ch) == EQUAL) nposdefaults++;
|
||||
if (TYPE(ch) == SLASH ) {
|
||||
nposonlyargs = nposargs;
|
||||
nposargs = 0;
|
||||
}
|
||||
}
|
||||
/* count the number of 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) == 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);
|
||||
if (!posargs && nposargs)
|
||||
return NULL;
|
||||
|
@ -1512,6 +1563,7 @@ ast_for_arguments(struct compiling *c, const node *n)
|
|||
i = 0;
|
||||
j = 0; /* index for defaults */
|
||||
k = 0; /* index for args */
|
||||
l = 0; /* index for posonlyargs */
|
||||
while (i < NCH(n)) {
|
||||
ch = CHILD(n, i);
|
||||
switch (TYPE(ch)) {
|
||||
|
@ -1537,11 +1589,23 @@ ast_for_arguments(struct compiling *c, const node *n)
|
|||
arg = ast_for_arg(c, ch);
|
||||
if (!arg)
|
||||
return NULL;
|
||||
asdl_seq_SET(posargs, k++, arg);
|
||||
if (l < nposonlyargs) {
|
||||
asdl_seq_SET(posonlyargs, l++, arg);
|
||||
} else {
|
||||
asdl_seq_SET(posargs, k++, arg);
|
||||
}
|
||||
i += 1; /* the name */
|
||||
if (i < NCH(n) && TYPE(CHILD(n, i)) == COMMA)
|
||||
i += 1; /* the comma, if present */
|
||||
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:
|
||||
if (i+1 >= NCH(n) ||
|
||||
(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 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
|
||||
|
@ -1909,7 +1973,7 @@ ast_for_lambdef(struct compiling *c, const node *n)
|
|||
expr_ty expression;
|
||||
|
||||
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)
|
||||
return NULL;
|
||||
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;
|
||||
if (positional) {
|
||||
start = 0;
|
||||
end = co->co_argcount - defcount;
|
||||
end = co->co_posonlyargcount + co->co_argcount - defcount;
|
||||
}
|
||||
else {
|
||||
start = co->co_argcount;
|
||||
start = co->co_posonlyargcount + co->co_argcount;
|
||||
end = start + co->co_kwonlyargcount;
|
||||
}
|
||||
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 i;
|
||||
PyObject *sig, *kwonly_sig;
|
||||
Py_ssize_t co_posonlyargcount = co->co_posonlyargcount;
|
||||
Py_ssize_t co_argcount = co->co_argcount;
|
||||
Py_ssize_t total_positional = co_argcount + co_posonlyargcount;
|
||||
|
||||
assert((co->co_flags & CO_VARARGS) == 0);
|
||||
/* 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) {
|
||||
kwonly_given++;
|
||||
}
|
||||
}
|
||||
if (defcount) {
|
||||
Py_ssize_t atleast = co_argcount - defcount;
|
||||
Py_ssize_t atleast = total_positional - defcount;
|
||||
plural = 1;
|
||||
sig = PyUnicode_FromFormat("from %zd to %zd", atleast, co_argcount);
|
||||
sig = PyUnicode_FromFormat("from %zd to %zd", atleast, total_positional);
|
||||
}
|
||||
else {
|
||||
plural = (co_argcount != 1);
|
||||
sig = PyUnicode_FromFormat("%zd", co_argcount);
|
||||
plural = (total_positional != 1);
|
||||
sig = PyUnicode_FromFormat("%zd", total_positional);
|
||||
}
|
||||
if (sig == NULL)
|
||||
return;
|
||||
|
@ -3772,6 +3774,67 @@ too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
|
|||
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
|
||||
PyEval_EvalFrame() and _PyEval_EvalFrameDefault() you will need to adjust
|
||||
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;
|
||||
PyThreadState *tstate;
|
||||
PyObject *x, *u;
|
||||
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
|
||||
Py_ssize_t i, n;
|
||||
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount + co->co_posonlyargcount;
|
||||
Py_ssize_t i, j, n;
|
||||
PyObject *kwdict;
|
||||
|
||||
if (globals == NULL) {
|
||||
|
@ -3826,14 +3889,28 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
|||
kwdict = NULL;
|
||||
}
|
||||
|
||||
/* Copy positional arguments into local variables */
|
||||
if (argcount > co->co_argcount) {
|
||||
n = co->co_argcount;
|
||||
/* Copy positional only arguments into local variables */
|
||||
if (argcount > co->co_argcount + co->co_posonlyargcount) {
|
||||
n = co->co_posonlyargcount;
|
||||
}
|
||||
else {
|
||||
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];
|
||||
Py_INCREF(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
|
||||
normally interned this should almost always hit. */
|
||||
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];
|
||||
if (name == keyword) {
|
||||
goto kw_found;
|
||||
|
@ -3874,7 +3951,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
|||
}
|
||||
|
||||
/* 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];
|
||||
int cmp = PyObject_RichCompareBool( keyword, name, Py_EQ);
|
||||
if (cmp > 0) {
|
||||
|
@ -3887,6 +3964,11 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
|||
|
||||
assert(j >= total_args);
|
||||
if (kwdict == NULL) {
|
||||
|
||||
if (co->co_posonlyargcount && positional_only_passed_as_keyword(co, kwcount, kwnames)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%U() got an unexpected keyword argument '%S'",
|
||||
co->co_name, keyword);
|
||||
|
@ -3910,14 +3992,14 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
|||
}
|
||||
|
||||
/* 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);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Add missing positional arguments (copy default values from defs) */
|
||||
if (argcount < co->co_argcount) {
|
||||
Py_ssize_t m = co->co_argcount - defcount;
|
||||
if (argcount < co->co_posonlyargcount + co->co_argcount) {
|
||||
Py_ssize_t m = co->co_posonlyargcount + co->co_argcount - defcount;
|
||||
Py_ssize_t missing = 0;
|
||||
for (i = argcount; i < m; i++) {
|
||||
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) */
|
||||
if (co->co_kwonlyargcount > 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;
|
||||
if (GETLOCAL(i) != NULL)
|
||||
continue;
|
||||
|
|
|
@ -122,6 +122,7 @@ struct compiler_unit {
|
|||
PyObject *u_private; /* for private name mangling */
|
||||
|
||||
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 */
|
||||
/* Pointer to the most recently allocated block. By following b_list
|
||||
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));
|
||||
u->u_scope_type = scope_type;
|
||||
u->u_argcount = 0;
|
||||
u->u_posonlyargcount = 0;
|
||||
u->u_kwonlyargcount = 0;
|
||||
u->u_ste = PySymtable_Lookup(c->c_st, key);
|
||||
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_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
|
||||
c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
|
||||
VISIT_SEQ_IN_SCOPE(c, stmt, body);
|
||||
co = assemble(c, 1);
|
||||
|
@ -2507,6 +2510,7 @@ compiler_lambda(struct compiler *c, expr_ty e)
|
|||
return 0;
|
||||
|
||||
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);
|
||||
VISIT_IN_SCOPE(c, expr, e->v.Lambda.body);
|
||||
if (c->u->u_ste->ste_generator) {
|
||||
|
@ -5742,7 +5746,7 @@ makecode(struct compiler *c, struct assembler *a)
|
|||
Py_ssize_t nlocals;
|
||||
int nlocals_int;
|
||||
int flags;
|
||||
int argcount, kwonlyargcount, maxdepth;
|
||||
int argcount, posonlyargcount, kwonlyargcount, maxdepth;
|
||||
|
||||
consts = consts_dict_keys_inorder(c->u->u_consts);
|
||||
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);
|
||||
posonlyargcount = Py_SAFE_DOWNCAST(c->u->u_posonlyargcount, Py_ssize_t, int);
|
||||
kwonlyargcount = Py_SAFE_DOWNCAST(c->u->u_kwonlyargcount, Py_ssize_t, int);
|
||||
maxdepth = stackdepth(c);
|
||||
if (maxdepth < 0) {
|
||||
goto error;
|
||||
}
|
||||
co = PyCode_New(argcount, kwonlyargcount,
|
||||
co = PyCode_New(argcount, posonlyargcount, kwonlyargcount,
|
||||
nlocals_int, maxdepth, flags,
|
||||
bytecode, consts, names, varnames,
|
||||
freevars, cellvars,
|
||||
|
|
|
@ -15,15 +15,15 @@
|
|||
the appropriate bytes from M___main__.c. */
|
||||
|
||||
static unsigned char M___hello__[] = {
|
||||
227,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,
|
||||
0,64,0,0,0,115,16,0,0,0,100,0,90,0,101,1,
|
||||
100,1,131,1,1,0,100,2,83,0,41,3,84,122,12,72,
|
||||
101,108,108,111,32,119,111,114,108,100,33,78,41,2,218,11,
|
||||
105,110,105,116,105,97,108,105,122,101,100,218,5,112,114,105,
|
||||
110,116,169,0,114,3,0,0,0,114,3,0,0,0,250,22,
|
||||
46,47,84,111,111,108,115,47,102,114,101,101,122,101,47,102,
|
||||
108,97,103,46,112,121,218,8,60,109,111,100,117,108,101,62,
|
||||
1,0,0,0,115,2,0,0,0,4,1,
|
||||
227,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,2,0,0,0,64,0,0,0,115,16,0,0,0,100,0,
|
||||
90,0,101,1,100,1,131,1,1,0,100,2,83,0,41,3,
|
||||
84,122,12,72,101,108,108,111,32,119,111,114,108,100,33,78,
|
||||
41,2,218,11,105,110,105,116,105,97,108,105,122,101,100,218,
|
||||
5,112,114,105,110,116,169,0,114,3,0,0,0,114,3,0,
|
||||
0,0,250,20,84,111,111,108,115,47,102,114,101,101,122,101,
|
||||
47,102,108,97,103,46,112,121,218,8,60,109,111,100,117,108,
|
||||
101,62,1,0,0,0,115,2,0,0,0,4,1,
|
||||
};
|
||||
|
||||
#define SIZE (int)sizeof(M___hello__)
|
||||
|
|
File diff suppressed because it is too large
Load diff
2781
Python/importlib.h
generated
2781
Python/importlib.h
generated
File diff suppressed because it is too large
Load diff
4216
Python/importlib_external.h
generated
4216
Python/importlib_external.h
generated
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;
|
||||
W_TYPE(TYPE_CODE, p);
|
||||
w_long(co->co_argcount, p);
|
||||
w_long(co->co_posonlyargcount, p);
|
||||
w_long(co->co_kwonlyargcount, p);
|
||||
w_long(co->co_nlocals, p);
|
||||
w_long(co->co_stacksize, p);
|
||||
|
@ -1322,6 +1323,7 @@ r_object(RFILE *p)
|
|||
case TYPE_CODE:
|
||||
{
|
||||
int argcount;
|
||||
int posonlyargcount;
|
||||
int kwonlyargcount;
|
||||
int nlocals;
|
||||
int stacksize;
|
||||
|
@ -1347,6 +1349,10 @@ r_object(RFILE *p)
|
|||
argcount = (int)r_long(p);
|
||||
if (PyErr_Occurred())
|
||||
goto code_error;
|
||||
posonlyargcount = (int)r_long(p);
|
||||
if (PyErr_Occurred()) {
|
||||
goto code_error;
|
||||
}
|
||||
kwonlyargcount = (int)r_long(p);
|
||||
if (PyErr_Occurred())
|
||||
goto code_error;
|
||||
|
@ -1391,7 +1397,7 @@ r_object(RFILE *p)
|
|||
goto code_error;
|
||||
|
||||
v = (PyObject *) PyCode_New(
|
||||
argcount, kwonlyargcount,
|
||||
argcount, posonlyargcount, kwonlyargcount,
|
||||
nlocals, stacksize, flags,
|
||||
code, consts, names, varnames,
|
||||
freevars, cellvars, filename, name,
|
||||
|
|
|
@ -1653,6 +1653,8 @@ symtable_visit_arguments(struct symtable *st, arguments_ty a)
|
|||
/* skip default arguments inside function block
|
||||
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))
|
||||
return 0;
|
||||
if (a->kwonlyargs && !symtable_visit_params(st, a->kwonlyargs))
|
||||
|
|
|
@ -592,14 +592,18 @@ def _arg(self, t):
|
|||
def _arguments(self, t):
|
||||
first = True
|
||||
# normal arguments
|
||||
defaults = [None] * (len(t.args) - len(t.defaults)) + t.defaults
|
||||
for a, d in zip(t.args, defaults):
|
||||
all_args = t.posonlyargs + t.args
|
||||
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
|
||||
else: self.write(", ")
|
||||
self.dispatch(a)
|
||||
if d:
|
||||
self.write("=")
|
||||
self.dispatch(d)
|
||||
if index == len(t.posonlyargs):
|
||||
self.write(", /")
|
||||
|
||||
# varargs, or bare '*' if no varargs but keyword-only arguments present
|
||||
if t.vararg or t.kwonlyargs:
|
||||
|
|
Loading…
Reference in a new issue