Skip to content

Commit 38c5db5

Browse files
committed
[GR-18231] Add support for positional only parameters.
PullRequest: graalpython/759
2 parents 001f12b + f67230d commit 38c5db5

File tree

19 files changed

+1108
-70
lines changed

19 files changed

+1108
-70
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ language runtime. The main focus is on user-observable behavior of the engine.
99
* Jython Compatiblity: Implement importing Python code from inside JAR files by adding `path/to/jarfile.jar!path/inside/jar` to `sys.path`
1010
* Added support for date and time interop.
1111
* Added support for setting the time zone via `Context.Builder.timeZone`.
12+
* PEP 570 - Python Positional-Only Parameters implemented
1213

1314
## Version 19.3.0
1415

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+
}

0 commit comments

Comments
 (0)