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 [',']]]
|
||||
|
|
|
@ -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 PythonValuesTestCase(unittest.TestCase):
|
|||
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 @@ _code_type = type(_write_atomic.__code__)
|
|||
# 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 @@ _code_type = type(_write_atomic.__code__)
|
|||
# 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 formatannotationrelativeto(object):
|
|||
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 formatargspec(args, varargs=None, varkw=None, defaults=None,
|
|||
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 @@ class ModuleFinder:
|
|||
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 @@ import sys, inspect
|
|||
# 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 @@ class cls135:
|
|||
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 @@ class AST_Tests(unittest.TestCase):
|
|||
|
||||
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 @@ class ASTValidatorTests(unittest.TestCase):
|
|||
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 @@ class ASTValidatorTests(unittest.TestCase):
|
|||
"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 @@ class ASTValidatorTests(unittest.TestCase):
|
|||
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 @@ exec_results = [
|
|||
('Module', [('Expr', (1, 0), ('DictComp', (1, 0), ('Name', (1, 1), 'a', ('Load',)), ('Name', (1, 5), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'v', ('Store',)), ('Name', (1, 13), 'w', ('Store',))], ('Store',)), ('Name', (1, 18), 'x', ('Load',)), [], 0)]))], []),
|
||||
('Module', [('Expr', (1, 0), ('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 @@ eval_results = [
|
|||
('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 @@ consts: ('None', '<code object g>', "'f.<locals>.g'")
|
|||
>>> dump(f(4).__code__)
|
||||
name: g
|
||||
argcount: 1
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 0
|
||||
names: ()
|
||||
varnames: ('y',)
|
||||
|
@ -40,6 +42,7 @@ consts: ('None',)
|
|||
>>> dump(h.__code__)
|
||||
name: h
|
||||
argcount: 2
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 0
|
||||
names: ()
|
||||
varnames: ('x', 'y', 'a', 'b', 'c')
|
||||
|
@ -57,6 +60,7 @@ consts: ('None',)
|
|||
>>> dump(attrs.__code__)
|
||||
name: attrs
|
||||
argcount: 1
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 0
|
||||
names: ('print', 'attr1', 'attr2', 'attr3')
|
||||
varnames: ('obj',)
|
||||
|
@ -75,6 +79,7 @@ consts: ('None',)
|
|||
>>> dump(optimize_away.__code__)
|
||||
name: optimize_away
|
||||
argcount: 0
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 0
|
||||
names: ()
|
||||
varnames: ()
|
||||
|
@ -91,6 +96,7 @@ consts: ("'doc string'", 'None')
|
|||
>>> dump(keywordonly_args.__code__)
|
||||
name: keywordonly_args
|
||||
argcount: 2
|
||||
posonlyargcount: 0
|
||||
kwonlyargcount: 1
|
||||
names: ()
|
||||
varnames: ('a', 'b', 'k1')
|
||||
|
@ -100,6 +106,23 @@ nlocals: 3
|
|||
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 @@ class CodeTest(unittest.TestCase):
|
|||
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 @@ code_info_code_info = """\
|
|||
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 @@ Variable names:
|
|||
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 @@ Names:
|
|||
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 @@ code_info_simple_stmt_str = """\
|
|||
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 @@ code_info_compound_stmt_str = """\
|
|||
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 @@ code_info_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 @@ class TestPartialMethod(unittest.TestCase):
|
|||
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 @@ func_filename = func.__code__.co_filename
|
|||
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 @@ class MagicNumberTests(unittest.TestCase):
|
|||
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 @@ class TestClassesAndFunctions(unittest.TestCase):
|
|||
|
||||
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 @@ class TestClassesAndFunctions(unittest.TestCase):
|
|||
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 @@ class TestClassesAndFunctions(unittest.TestCase):
|
|||
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 @@ class TestClassesAndFunctions(unittest.TestCase):
|
|||
@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 @@ class RoundtripLegalSyntaxTestCase(unittest.TestCase):
|
|||
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")
|
||||
|
|
|
@ -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 @@ failed:
|
|||
#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)
|
||||
|
|
|
@ -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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -530,6 +530,7 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
|
|||
PyCodeObject *co = (PyCodeObject *)v;
|
||||
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 @@ class Unparser:
|
|||
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 New Issue