mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 08:24:40 +01:00
Merge pull request #3720 from laloch/pos-only-args
Add support for PEP 570 positional-only parameters
This commit is contained in:
commit
b30448b300
4 changed files with 139 additions and 17 deletions
23
news/pos-only-args.rst
Normal file
23
news/pos-only-args.rst
Normal file
|
@ -0,0 +1,23 @@
|
|||
**Added:**
|
||||
|
||||
* Support for PEP 570 positional-only parameters.
|
||||
|
||||
**Changed:**
|
||||
|
||||
* <news item>
|
||||
|
||||
**Deprecated:**
|
||||
|
||||
* <news item>
|
||||
|
||||
**Removed:**
|
||||
|
||||
* <news item>
|
||||
|
||||
**Fixed:**
|
||||
|
||||
* <news item>
|
||||
|
||||
**Security:**
|
||||
|
||||
* <news item>
|
|
@ -11,7 +11,7 @@ from xonsh.ast import AST, With, Pass, Str, Call
|
|||
from xonsh.parser import Parser
|
||||
from xonsh.parsers.fstring_adaptor import FStringAdaptor
|
||||
|
||||
from tools import nodes_equal, skip_if_no_walrus, VER_MAJOR_MINOR
|
||||
from tools import nodes_equal, skip_if_pre_3_8, VER_MAJOR_MINOR
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
@ -1041,6 +1041,11 @@ def test_lambda_x_star_y_kwargs():
|
|||
check_ast("lambda x, *, y, **kwargs: 42")
|
||||
|
||||
|
||||
@skip_if_pre_3_8
|
||||
def test_lambda_x_divide_y_star_z_kwargs():
|
||||
check_ast("lambda x, /, y, *, z, **kwargs: 42")
|
||||
|
||||
|
||||
def test_call_range():
|
||||
check_ast("range(6)")
|
||||
|
||||
|
@ -1209,12 +1214,12 @@ def test_rshift_op_three():
|
|||
check_ast("42 >> 65 >> 1 >> 7")
|
||||
|
||||
|
||||
@skip_if_no_walrus
|
||||
@skip_if_pre_3_8
|
||||
def test_named_expr():
|
||||
check_ast("(x := 42)")
|
||||
|
||||
|
||||
@skip_if_no_walrus
|
||||
@skip_if_pre_3_8
|
||||
def test_named_expr_list():
|
||||
check_ast("[x := 42, x + 1, x + 2]")
|
||||
|
||||
|
@ -1560,10 +1565,7 @@ def test_yield_x_y():
|
|||
check_stmts("yield x, y", False)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
VER_MAJOR_MINOR < (3, 8),
|
||||
reason="Python 3.8 feature"
|
||||
)
|
||||
@skip_if_pre_3_8
|
||||
def test_return_x_starexpr():
|
||||
check_stmts("yield x, *[y, z]", False)
|
||||
|
||||
|
@ -1588,10 +1590,7 @@ def test_return_x_y():
|
|||
check_stmts("return x, y", False)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
VER_MAJOR_MINOR < (3, 8),
|
||||
reason="Python 3.8 feature"
|
||||
)
|
||||
@skip_if_pre_3_8
|
||||
def test_return_x_starexpr():
|
||||
check_stmts("return x, *[y, z]", False)
|
||||
|
||||
|
@ -1943,6 +1942,16 @@ def test_func_x_star_y_kwargs():
|
|||
check_stmts("def f(x, *, y, **kwargs):\n return 42")
|
||||
|
||||
|
||||
@skip_if_pre_3_8
|
||||
def test_func_x_divide():
|
||||
check_stmts("def f(x, /):\n return 42")
|
||||
|
||||
|
||||
@skip_if_pre_3_8
|
||||
def test_func_x_divide_y_star_z_kwargs():
|
||||
check_stmts("def f(x, /, y, *, z, **kwargs):\n return 42")
|
||||
|
||||
|
||||
def test_func_tx():
|
||||
check_stmts("def f(x:int):\n return x")
|
||||
|
||||
|
@ -2049,22 +2058,22 @@ def test_async_await():
|
|||
check_stmts("async def f():\n await fut\n", False)
|
||||
|
||||
|
||||
@skip_if_no_walrus
|
||||
@skip_if_pre_3_8
|
||||
def test_named_expr_args():
|
||||
check_stmts("id(x := 42)")
|
||||
|
||||
|
||||
@skip_if_no_walrus
|
||||
@skip_if_pre_3_8
|
||||
def test_named_expr_if():
|
||||
check_stmts("if (x := 42) > 0:\n x += 1")
|
||||
|
||||
|
||||
@skip_if_no_walrus
|
||||
@skip_if_pre_3_8
|
||||
def test_named_expr_elif():
|
||||
check_stmts("if False:\n pass\nelif x := 42:\n x += 1")
|
||||
|
||||
|
||||
@skip_if_no_walrus
|
||||
@skip_if_pre_3_8
|
||||
def test_named_expr_while():
|
||||
check_stmts("y = 42\nwhile (x := y) < 43:\n y += 1")
|
||||
|
||||
|
@ -3128,3 +3137,11 @@ def test_syntax_error_augassign_cmp(exp):
|
|||
def test_syntax_error_bar_kwonlyargs():
|
||||
with pytest.raises(SyntaxError):
|
||||
PARSER.parse("def spam(*):\n pass\n", mode="exec")
|
||||
|
||||
def test_syntax_error_bar_posonlyargs():
|
||||
with pytest.raises(SyntaxError):
|
||||
PARSER.parse("def spam(/):\n pass\n", mode="exec")
|
||||
|
||||
def test_syntax_error_bar_posonlyargs_no_comma():
|
||||
with pytest.raises(SyntaxError):
|
||||
PARSER.parse("def spam(x /, y):\n pass\n", mode="exec")
|
||||
|
|
|
@ -30,7 +30,6 @@ ON_AZURE_PIPELINES = os.environ.get("TF_BUILD", "") == "True"
|
|||
print("ON_AZURE_PIPELINES", repr(ON_AZURE_PIPELINES))
|
||||
print("os.environ['TF_BUILD']", repr(os.environ.get("TF_BUILD", "")))
|
||||
TEST_DIR = os.path.dirname(__file__)
|
||||
HAS_WALRUS = VER_FULL > (3, 8)
|
||||
|
||||
# pytest skip decorators
|
||||
skip_if_on_conda = pytest.mark.skipif(
|
||||
|
@ -53,7 +52,7 @@ skip_if_on_darwin = pytest.mark.skipif(ON_DARWIN, reason="not Mac friendly")
|
|||
|
||||
skip_if_on_travis = pytest.mark.skipif(ON_TRAVIS, reason="not Travis CI friendly")
|
||||
|
||||
skip_if_no_walrus = pytest.mark.skipif(not HAS_WALRUS, reason="no assignment expr.")
|
||||
skip_if_pre_3_8 = pytest.mark.skipif(VER_FULL < (3, 8), reason="Python >= 3.8 feature")
|
||||
|
||||
|
||||
def sp(cmd):
|
||||
|
|
|
@ -51,6 +51,31 @@ class Parser(ThreeSixParser):
|
|||
outputdir=outputdir,
|
||||
)
|
||||
|
||||
def _set_posonly_args_def(self, argmts, vals):
|
||||
for v in vals:
|
||||
argmts.posonlyargs.append(v["arg"])
|
||||
d = v["default"]
|
||||
if d is not None:
|
||||
argmts.defaults.append(d)
|
||||
|
||||
def _set_posonly_args(self, p0, p1, p2, p3):
|
||||
if p2 is None and p3 is None:
|
||||
# x
|
||||
p0.posonlyargs.append(p1)
|
||||
elif p2 is not None and p3 is None:
|
||||
# x=42
|
||||
p0.posonlyargs.append(p1)
|
||||
p0.defaults.append(p2)
|
||||
elif p2 is None and p3 is not None:
|
||||
# x, y and x, y=42
|
||||
p0.posonlyargs.append(p1)
|
||||
self._set_posonly_args_def(p0, p3)
|
||||
else:
|
||||
# x=42, y=42
|
||||
p0.posonlyargs.append(p1)
|
||||
p0.defaults.append(p2)
|
||||
self._set_posonly_args_def(p0, p3)
|
||||
|
||||
def p_parameters(self, p):
|
||||
"""parameters : LPAREN typedargslist_opt RPAREN"""
|
||||
p2 = p[2]
|
||||
|
@ -214,6 +239,35 @@ class Parser(ThreeSixParser):
|
|||
self._set_var_args(p0, p[6], p[7])
|
||||
p[0] = p0
|
||||
|
||||
def p_typedargslist_t12(self, p):
|
||||
"""typedargslist : posonlyargslist comma_opt
|
||||
| posonlyargslist COMMA typedargslist
|
||||
"""
|
||||
if len(p) == 4:
|
||||
p0 = p[3]
|
||||
p0.posonlyargs = p[1].posonlyargs
|
||||
else:
|
||||
p0 = p[1]
|
||||
p[0] = p0
|
||||
|
||||
def p_posonlyargslist(self, p):
|
||||
"""posonlyargslist : tfpdef equals_test_opt COMMA DIVIDE
|
||||
| tfpdef equals_test_opt comma_tfpdef_list COMMA DIVIDE"""
|
||||
p0 = ast.arguments(
|
||||
posonlyargs=[],
|
||||
args=[],
|
||||
vararg=None,
|
||||
kwonlyargs=[],
|
||||
kw_defaults=[],
|
||||
kwarg=None,
|
||||
defaults=[],
|
||||
)
|
||||
if p[3] == ",":
|
||||
self._set_posonly_args(p0, p[1], p[2], None)
|
||||
else:
|
||||
self._set_posonly_args(p0, p[1], p[2], p[3])
|
||||
p[0] = p0
|
||||
|
||||
def p_varargslist_kwargs(self, p):
|
||||
"""varargslist : POW vfpdef"""
|
||||
p[0] = ast.arguments(
|
||||
|
@ -332,6 +386,35 @@ class Parser(ThreeSixParser):
|
|||
self._set_var_args(p0, p[6], p[7])
|
||||
p[0] = p0
|
||||
|
||||
def p_varargslist_t12(self, p):
|
||||
"""varargslist : posonlyvarargslist comma_opt
|
||||
| posonlyvarargslist COMMA varargslist
|
||||
"""
|
||||
if len(p) == 4:
|
||||
p0 = p[3]
|
||||
p0.posonlyargs = p[1].posonlyargs
|
||||
else:
|
||||
p0 = p[1]
|
||||
p[0] = p0
|
||||
|
||||
def p_posonlyvarargslist(self, p):
|
||||
"""posonlyvarargslist : vfpdef equals_test_opt COMMA DIVIDE
|
||||
| vfpdef equals_test_opt comma_vfpdef_list COMMA DIVIDE"""
|
||||
p0 = ast.arguments(
|
||||
posonlyargs=[],
|
||||
args=[],
|
||||
vararg=None,
|
||||
kwonlyargs=[],
|
||||
kw_defaults=[],
|
||||
kwarg=None,
|
||||
defaults=[],
|
||||
)
|
||||
if p[3] == ",":
|
||||
self._set_posonly_args(p0, p[1], p[2], None)
|
||||
else:
|
||||
self._set_posonly_args(p0, p[1], p[2], p[3])
|
||||
p[0] = p0
|
||||
|
||||
def p_lambdef(self, p):
|
||||
"""lambdef : lambda_tok varargslist_opt COLON test"""
|
||||
p1, p2, p4 = p[1], p[2], p[4]
|
||||
|
|
Loading…
Add table
Reference in a new issue