Skip to content

Commit e03a278

Browse files
committed
Handling positional arg only in lambdas
Adding tests. Fixes for: [GR-19992] Error message shows wrong type of arguments. [GR-19934] SyntaxError duplicate arguments is not raised.
1 parent 7ddf868 commit e03a278

File tree

12 files changed

+473
-85
lines changed

12 files changed

+473
-85
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/*
2+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.test.grammar;
42+
43+
import com.oracle.graal.python.test.PythonTests;
44+
import org.junit.Test;
45+
46+
public class PositionalOnlyArgTests {
47+
48+
@Test
49+
public void optionalPositionalOnly01() {
50+
String source = "def f(a, b=10, /, c=100):\n" +
51+
" return a + b + c\n" +
52+
"print(f(1, 2, 3))";
53+
PythonTests.assertPrints("6\n", source);
54+
}
55+
56+
@Test
57+
public void optionalPositionalOnly02() {
58+
String source = "def f(a, b=10, /, c=100):\n" +
59+
" return a + b + c\n" +
60+
"print(f(1, 2, c=3))";
61+
PythonTests.assertPrints("6\n", source);
62+
}
63+
64+
@Test
65+
public void optionalPositionalOnly03() {
66+
String source = "def f(a, b=10, /, c=100):\n" +
67+
" return a + b + c\n" +
68+
"print(f(1, b=2, c=100))";
69+
PythonTests.assertLastLineError("TypeError: f() got some positional-only arguments passed as keyword arguments: 'b'", source);
70+
}
71+
72+
@Test
73+
public void optionalPositionalOnly04() {
74+
String source = "def f(a, b=10, /, c=100):\n" +
75+
" return a + b + c\n" +
76+
"print(f(1, b=2))";
77+
PythonTests.assertLastLineError("TypeError: f() got some positional-only arguments passed as keyword arguments: 'b'", source);
78+
}
79+
80+
@Test
81+
public void optionalPositionalOnly05() {
82+
String source = "def f(a, b=10, /, c=100):\n" +
83+
" return a + b + c\n" +
84+
"print(f(1, c=2))";
85+
PythonTests.assertPrints("13\n", source);
86+
}
87+
88+
@Test
89+
public void posOnlyDefinition01() {
90+
String source = "def f(a, b, c, /, d, e=1, *, f, g=2):\n" +
91+
" pass\n" +
92+
"print(f.__code__.co_argcount)\n" +
93+
"print(f.__code__.co_posonlyargcount)\n" +
94+
"print(f.__defaults__)";
95+
PythonTests.assertPrints("5\n3\n(1,)\n", source);
96+
}
97+
98+
@Test
99+
public void posOnlyDefinition02() {
100+
String source = "def f(a, b, c=1, /, d=2, e=3, *, f, g=4):\n" +
101+
" pass\n" +
102+
"print(f.__code__.co_argcount)\n" +
103+
"print(f.__code__.co_posonlyargcount)\n" +
104+
"print(f.__defaults__)";
105+
PythonTests.assertPrints("5\n3\n(1, 2, 3)\n", source);
106+
}
107+
108+
@Test
109+
public void invalidCall01() {
110+
String source = "def f(a, b, /, c):\n" +
111+
" pass\n" +
112+
"f(1, 2)";
113+
PythonTests.assertLastLineError("TypeError: f() missing 1 required positional argument: 'c'", source);
114+
}
115+
116+
@Test
117+
public void invalidCall02() {
118+
String source = "def f(a, b, /, c):\n" +
119+
" pass\n" +
120+
"f(1)";
121+
PythonTests.assertLastLineError("TypeError: f() missing 2 required positional arguments: 'b' and 'c'", source);
122+
}
123+
124+
@Test
125+
public void invalidCall03() {
126+
String source = "def f(a, b, /, c):\n" +
127+
" pass\n" +
128+
"f()";
129+
PythonTests.assertLastLineError("TypeError: f() missing 3 required positional arguments: 'a', 'b', and 'c'", source);
130+
}
131+
132+
@Test
133+
public void invalidCall04() {
134+
String source = "def f(a, b, /, c):\n" +
135+
" pass\n" +
136+
"f(1,2,3,4)";
137+
PythonTests.assertLastLineError("TypeError: f() takes 3 positional arguments but 4 were given", source);
138+
}
139+
140+
@Test
141+
public void invalidCall05() {
142+
String source = "def f(a, b, /, c=3):" +
143+
" pass\n" +
144+
"f(1)";
145+
PythonTests.assertLastLineError("TypeError: f() missing 1 required positional argument: 'b'", source);
146+
}
147+
148+
@Test
149+
public void invalidCall06() {
150+
String source = "def f(a, b, /, c=3):" +
151+
" pass\n" +
152+
"f()";
153+
PythonTests.assertLastLineError("TypeError: f() missing 2 required positional arguments: 'a' and 'b'", source);
154+
}
155+
156+
@Test
157+
public void invalidCall07() {
158+
String source = "def f(a, b, /, c=3):" +
159+
" pass\n" +
160+
"f(1,2,3,4)";
161+
PythonTests.assertLastLineError("TypeError: f() takes from 2 to 3 positional arguments but 4 were given", source);
162+
}
163+
164+
@Test
165+
public void invalidCall08() {
166+
String source = "def f(a, b, /, c, *, d, e):" +
167+
" pass\n" +
168+
"f(1, 2, 3, e=2)";
169+
PythonTests.assertLastLineError("TypeError: f() missing 1 required keyword-only argument: 'd'", source);
170+
}
171+
172+
@Test
173+
public void invalidCall09() {
174+
String source = "def f(a, b, /, c, *, d, e):" +
175+
" pass\n" +
176+
"f(1, 2, 3)";
177+
PythonTests.assertLastLineError("TypeError: f() missing 2 required keyword-only arguments: 'd' and 'e'", source);
178+
}
179+
180+
@Test
181+
public void invalidCall10() {
182+
String source = "def f(a, b, /, c, *, d, e):" +
183+
" pass\n" +
184+
"f(1, 2)";
185+
PythonTests.assertLastLineError("TypeError: f() missing 1 required positional argument: 'c'", source);
186+
}
187+
188+
@Test
189+
public void invalidCall11() {
190+
String source = "def f(a, b, /, c, *, d, e):" +
191+
" pass\n" +
192+
"f(1)";
193+
PythonTests.assertLastLineError("TypeError: f() missing 2 required positional arguments: 'b' and 'c'", source);
194+
}
195+
196+
@Test
197+
public void invalidCall12() {
198+
String source = "def f(a, b, /, c, *, d, e):" +
199+
" pass\n" +
200+
"f()";
201+
PythonTests.assertLastLineError("TypeError: f() missing 3 required positional arguments: 'a', 'b', and 'c'", source);
202+
}
203+
204+
@Test
205+
public void invalidCall13() {
206+
String source = "def f(a, b, /, c, *, d, e):" +
207+
" pass\n" +
208+
"f(1, 2, 3, 4, 5, 6, d=7, e=8)";
209+
PythonTests.assertLastLineError("TypeError: f() takes 3 positional arguments but 6 positional arguments (and 2 keyword-only arguments) were given", source);
210+
}
211+
212+
@Test
213+
public void invalidCall14() {
214+
String source = "def f(a, b, /, c, *, d, e):" +
215+
" pass\n" +
216+
"f(1, 2, 3, d=1, e=4, f=56)";
217+
PythonTests.assertLastLineError("TypeError: f() got an unexpected keyword argument 'f'", source);
218+
}
219+
220+
@Test
221+
public void lambda01() {
222+
String source = "x = lambda a, /, b: a + b\n" +
223+
"print(x(1,2))\n" +
224+
"print(x(1,b=2))";
225+
PythonTests.assertPrints("3\n3\n", source);
226+
}
227+
228+
@Test
229+
public void lambda02() {
230+
String source = "x = lambda a, /, b=2: a + b\n" +
231+
"print(x(1))";
232+
PythonTests.assertPrints("3\n", source);
233+
}
234+
235+
@Test
236+
public void lambda03() {
237+
String source = "x = lambda a, b, /: a + b\n" +
238+
"print(x(1, 2))";
239+
PythonTests.assertPrints("3\n", source);
240+
}
241+
242+
@Test
243+
public void lambda04() {
244+
String source = "x = lambda a, b, /, : a + b\n" +
245+
"print(x(1, 2))";
246+
PythonTests.assertPrints("3\n", source);
247+
}
248+
}

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/parser/FuncDefTests.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class FuncDefTests extends ParserTestBase {
5050
public void args01() throws Exception {
5151
checkScopeAndTree("def fn(a, b=0, *arg, k1, k2=0): return a + b + k1 + k2 + sum(arg)");
5252
}
53-
53+
5454
@Test
5555
public void args02() throws Exception {
5656
checkSyntaxErrorMessage("def f(a, a): pass", "SyntaxError: duplicate argument 'a' in function definition");
@@ -236,47 +236,47 @@ public void recursion02() throws Exception {
236236
public void positionalOnlyArg01() throws Exception {
237237
checkTreeResult("def name(p1, p2, /, p_or_kw, *, kw): pass");
238238
}
239-
239+
240240
@Test
241241
public void positionalOnlyArg02() throws Exception {
242242
checkTreeResult("def name(p1, p2=None, /, p_or_kw=None, *, kw): pass");
243243
}
244-
244+
245245
@Test
246246
public void positionalOnlyArg03() throws Exception {
247247
checkTreeResult("def name(p1, p2=None, /, *, kw): pass");
248248
}
249-
249+
250250
@Test
251251
public void positionalOnlyArg04() throws Exception {
252252
checkTreeResult("def name(p1, p2=None, /): pass");
253253
}
254-
254+
255255
@Test
256256
public void positionalOnlyArg05() throws Exception {
257257
checkTreeResult("def name(p1, p2, /, p_or_kw): pass");
258258
}
259-
259+
260260
@Test
261261
public void positionalOnlyArg06() throws Exception {
262262
checkTreeResult("def name(p1, p2, /): pass");
263263
}
264-
264+
265265
@Test
266266
public void positionalOnlyArg07() throws Exception {
267267
checkSyntaxErrorMessage("def name(p1, p2=None, /, p_or_kw, *, kw): pass", "SyntaxError: non-default argument follows default argument");
268268
}
269-
269+
270270
@Test
271271
public void positionalOnlyArg08() throws Exception {
272272
checkSyntaxErrorMessage("def name(p1=None, p2, /, p_or_kw=None, *, kw): pass", "SyntaxError: non-default argument follows default argument");
273273
}
274-
274+
275275
@Test
276276
public void positionalOnlyArg09() throws Exception {
277277
checkSyntaxErrorMessage("def name(p1=None, p2, /): pass", "SyntaxError: non-default argument follows default argument");
278278
}
279-
279+
280280
@Test
281281
public void positionalOnlyArg10() throws Exception {
282282
checkSyntaxErrorMessage("def f(a, b = 5, /, c): pass", "SyntaxError: non-default argument follows default argument");
@@ -296,7 +296,7 @@ public void positionalOnlyArg12() throws Exception {
296296
public void positionalOnlyArg13() throws Exception {
297297
checkSyntaxErrorMessage("def f(a = 5, b, /): pass", "SyntaxError: non-default argument follows default argument");
298298
}
299-
299+
300300
@Test
301301
public void positionalOnlyArg14() throws Exception {
302302
checkSyntaxError("def f(*args, /): pass");
@@ -306,7 +306,7 @@ public void positionalOnlyArg14() throws Exception {
306306
public void positionalOnlyArg15() throws Exception {
307307
checkSyntaxError("def f(*args, a, /): pass");
308308
}
309-
309+
310310
@Test
311311
public void positionalOnlyArg16() throws Exception {
312312
checkSyntaxError("def f(**kwargs, /): pass");
@@ -378,12 +378,12 @@ public void positionalOnlyArg29() throws Exception {
378378
}
379379

380380
@Test
381-
public void positionalOnlyArg30() throws Exception {
381+
public void positionalOnlyArg30() throws Exception {
382382
checkSyntaxErrorMessage("async def f(a = 5, b, /, c): pass", "SyntaxError: non-default argument follows default argument");
383383
}
384384

385385
@Test
386-
public void positionalOnlyArg31() throws Exception {
386+
public void positionalOnlyArg31() throws Exception {
387387
checkSyntaxErrorMessage("async def f(a = 5, b=1, /, c, d=2): pass", "SyntaxError: non-default argument follows default argument");
388388
}
389389

@@ -466,7 +466,7 @@ public void positionalOnlyArg46() throws Exception {
466466
public void positionalOnlyArg47() throws Exception {
467467
checkSyntaxError("async def f(a, *, c, /, d, e): pass");
468468
}
469-
469+
470470
private void checkScopeAndTree() throws Exception {
471471
File testFile = getTestFileFromTestAndTestMethod();
472472
checkScopeFromFile(testFile, true);

0 commit comments

Comments
 (0)