Skip to content

Commit fa2fbf2

Browse files
committed
[GR-22223] Few fixes to drive test runs on other Python's running tox on GraalPython.
PullRequest: graalpython/939
2 parents 000a1c3 + eb4a82d commit fa2fbf2

File tree

15 files changed

+364
-157
lines changed

15 files changed

+364
-157
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_posix.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ def create_file(self):
102102
os.chmod(new_file_path, st.st_mode | stat.S_IEXEC)
103103
return new_file_path, cwd
104104

105+
def test_empty_stat(self):
106+
try:
107+
os.stat("")
108+
except FileNotFoundError:
109+
assert True
110+
else:
111+
assert False
112+
105113
def delete_file(self, new_file_path, cwd):
106114
os.remove(new_file_path)
107115
os.remove(cwd + '/test.txt')

graalpython/com.oracle.graal.python.test/src/tests/test_subprocess.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, 2019, Oracle and/or its affiliates.
1+
# Copyright (c) 2018, 2020, Oracle and/or its affiliates.
22
# Copyright (C) 1996-2017 Python Software Foundation
33
#
44
# Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
@@ -84,6 +84,7 @@ def test_kill(self):
8484
p = subprocess.Popen([sys.executable, "-c", "print('oh no')"])
8585
p.kill()
8686
assert True
87+
p.wait()
8788

8889
def test_waitpid(self):
8990
import os
@@ -92,3 +93,34 @@ def test_waitpid(self):
9293
assert os.waitpid(p.pid, os.WNOHANG) == (0, 0)
9394
finally:
9495
p.kill()
96+
p.wait()
97+
98+
def test_waitpid_group_child(self):
99+
import os
100+
p = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(0.1); 42"])
101+
res = os.waitpid(0, 0)
102+
assert res[1] == 0, res
103+
104+
def test_waitpid_any_child(self):
105+
import os
106+
p = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(0.1); 42"])
107+
res = os.waitpid(-1, 0)
108+
assert res[1] == 0, res
109+
110+
def test_waitpid_no_child(self):
111+
import os
112+
try:
113+
os.waitpid(-1, 0)
114+
except ChildProcessError:
115+
assert True
116+
else:
117+
assert False
118+
119+
def test_kill(self):
120+
import os
121+
p = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(2); 42"])
122+
try:
123+
assert os.kill(p.pid, 9) is None
124+
finally:
125+
p.kill()
126+
p.wait()

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -40,18 +40,115 @@
4040
*/
4141
package com.oracle.graal.python.builtins.modules;
4242

43-
import java.util.ArrayList;
43+
import java.io.IOException;
44+
import java.nio.channels.Channel;
45+
import java.nio.channels.FileChannel;
46+
import java.nio.channels.FileLock;
4447
import java.util.List;
4548

49+
import com.oracle.graal.python.builtins.Builtin;
4650
import com.oracle.graal.python.builtins.CoreFunctions;
4751
import com.oracle.graal.python.builtins.PythonBuiltins;
52+
import com.oracle.graal.python.builtins.objects.PNone;
53+
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum;
4854
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
55+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
56+
import com.oracle.graal.python.runtime.PosixResources;
57+
import com.oracle.graal.python.runtime.PythonCore;
58+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
59+
import com.oracle.truffle.api.dsl.Cached;
60+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
4961
import com.oracle.truffle.api.dsl.NodeFactory;
62+
import com.oracle.truffle.api.dsl.Specialization;
63+
import com.oracle.truffle.api.frame.VirtualFrame;
64+
import com.oracle.truffle.api.profiles.ValueProfile;
5065

5166
@CoreFunctions(defineModule = "fcntl")
5267
public class FcntlModuleBuiltins extends PythonBuiltins {
68+
private static final int LOCK_SH = 1;
69+
private static final int LOCK_EX = 2;
70+
private static final int LOCK_NB = 4;
71+
private static final int LOCK_UN = 8;
72+
5373
@Override
5474
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
55-
return new ArrayList<>();
75+
return FcntlModuleBuiltinsFactory.getFactories();
76+
}
77+
78+
@Override
79+
public void initialize(PythonCore core) {
80+
builtinConstants.put("LOCK_SH", LOCK_SH);
81+
builtinConstants.put("LOCK_EX", LOCK_EX);
82+
builtinConstants.put("LOCK_NB", LOCK_NB);
83+
builtinConstants.put("LOCK_UN", LOCK_UN);
84+
super.initialize(core);
85+
}
86+
87+
@Builtin(name = "flock", minNumOfPositionalArgs = 2)
88+
@GenerateNodeFactory
89+
abstract static class FlockNode extends PythonBinaryBuiltinNode {
90+
@Specialization
91+
synchronized PNone flock(VirtualFrame frame, int fd, int operation,
92+
@Cached("createClassProfile()") ValueProfile profile) {
93+
PosixResources rs = getContext().getResources();
94+
Channel channel;
95+
try {
96+
channel = rs.getFileChannel(fd, profile);
97+
} catch (IndexOutOfBoundsException e) {
98+
throw raiseOSError(frame, OSErrorEnum.EBADFD);
99+
}
100+
if (channel instanceof FileChannel) {
101+
FileChannel fc = (FileChannel) channel;
102+
FileLock lock = rs.getFileLock(fd);
103+
try {
104+
lock = doLockOperation(operation, fc, lock);
105+
} catch (IOException e) {
106+
throw raiseOSError(frame, e);
107+
}
108+
rs.setFileLock(fd, lock);
109+
}
110+
return PNone.NONE;
111+
}
112+
113+
@TruffleBoundary
114+
private static FileLock doLockOperation(int operation, FileChannel fc, FileLock oldLock) throws IOException {
115+
FileLock lock = oldLock;
116+
if (lock == null) {
117+
if ((operation & LOCK_SH) != 0) {
118+
if ((operation & LOCK_NB) != 0) {
119+
lock = fc.tryLock(0, Long.MAX_VALUE, true);
120+
} else {
121+
lock = fc.lock(0, Long.MAX_VALUE, true);
122+
}
123+
} else if ((operation & LOCK_EX) != 0) {
124+
if ((operation & LOCK_NB) != 0) {
125+
lock = fc.tryLock();
126+
} else {
127+
lock = fc.lock();
128+
}
129+
} else {
130+
// not locked, that's ok
131+
}
132+
} else {
133+
if ((operation & LOCK_UN) != 0) {
134+
lock.release();
135+
lock = null;
136+
} else if ((operation & LOCK_EX) != 0) {
137+
if (lock.isShared()) {
138+
if ((operation & LOCK_NB) != 0) {
139+
FileLock newLock = fc.tryLock();
140+
if (newLock != null) {
141+
lock = newLock;
142+
}
143+
} else {
144+
lock = fc.lock();
145+
}
146+
}
147+
} else {
148+
// we already have a suitable lock
149+
}
150+
}
151+
return lock;
152+
}
56153
}
57154
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,9 @@ long fileTimeToSeconds(FileTime t) {
565565
}
566566

567567
Object stat(VirtualFrame frame, String path, boolean followSymlinks) {
568+
if (path.isEmpty()) {
569+
throw raiseOSError(frame, OSErrorEnum.ENOENT);
570+
}
568571
try {
569572
return statInternal(path, followSymlinks);
570573
} catch (Exception e) {
@@ -1483,7 +1486,11 @@ PTuple waitpid(VirtualFrame frame, int pid, int options) {
14831486
throw raise(PythonBuiltinClassType.NotImplementedError, "Only 0 or WNOHANG are supported for waitpid");
14841487
}
14851488
} catch (IndexOutOfBoundsException e) {
1486-
throw raiseOSError(frame, OSErrorEnum.ESRCH);
1489+
if (pid <= 0) {
1490+
throw raiseOSError(frame, OSErrorEnum.ECHILD);
1491+
} else {
1492+
throw raiseOSError(frame, OSErrorEnum.ESRCH);
1493+
}
14871494
} catch (InterruptedException e) {
14881495
throw raiseOSError(frame, OSErrorEnum.EINTR);
14891496
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixSubprocessModuleBuiltins.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
import com.oracle.graal.python.builtins.objects.PNone;
6060
import com.oracle.graal.python.builtins.objects.bytes.BytesNodes;
6161
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
62+
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum;
63+
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.ErrorAndMessagePair;
6264
import com.oracle.graal.python.builtins.objects.function.PArguments;
6365
import com.oracle.graal.python.builtins.objects.list.PList;
6466
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
@@ -219,8 +221,9 @@ private synchronized int forkExec(PList args, @SuppressWarnings("unused") PList
219221
if (!(err instanceof WritableByteChannel)) {
220222
throw raise(PythonBuiltinClassType.OSError, "there was an error writing the fork_exec error to the error pipe");
221223
} else {
224+
ErrorAndMessagePair pair = OSErrorEnum.fromException(e);
222225
try {
223-
((WritableByteChannel) err).write(ByteBuffer.wrap(("SubprocessError:0:" + e.getMessage()).getBytes()));
226+
((WritableByteChannel) err).write(ByteBuffer.wrap(("OSError:" + Long.toHexString(pair.oserror.getNumber()) + ":" + pair.message).getBytes()));
224227
} catch (IOException e1) {
225228
}
226229
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/OSErrorEnum.java

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,25 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.exception;
4242

43+
import java.io.FileNotFoundException;
44+
import java.io.IOException;
45+
import java.nio.channels.ClosedChannelException;
46+
import java.nio.channels.NonReadableChannelException;
47+
import java.nio.channels.NonWritableChannelException;
48+
import java.nio.file.AccessDeniedException;
49+
import java.nio.file.DirectoryNotEmptyException;
50+
import java.nio.file.FileAlreadyExistsException;
51+
import java.nio.file.FileSystemException;
52+
import java.nio.file.FileSystemLoopException;
53+
import java.nio.file.NoSuchFileException;
54+
import java.nio.file.NotDirectoryException;
55+
import java.nio.file.NotLinkException;
56+
import java.util.regex.Matcher;
57+
import java.util.regex.Pattern;
58+
59+
import com.oracle.truffle.api.CompilerDirectives;
4360
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
61+
import com.oracle.truffle.api.CompilerDirectives.ValueType;
4462

4563
public enum OSErrorEnum {
4664

@@ -50,7 +68,7 @@ public enum OSErrorEnum {
5068
* <pre>
5169
* awk -F'\\s+' '/#define/ { printf("%s(%s, \"",$2,$3); for (i=5; i<=NF-1; i++) {if(i==5){printf("%s",$i);}else{printf("%s%s",sep,$i);} sep=OFS}; print "\")," }' /usr/include/asm-generic/errno*
5270
* </pre>
53-
*
71+
*
5472
* Manually are changed EWOULDBLOCK and EDEADLOCK and move before appropriate errors with the
5573
* same number, because ErrnoModuleBuiltins and PosixModuleBuiltins built a dictionary from this
5674
* enum.
@@ -222,11 +240,93 @@ public static OSErrorEnum fromMessage(String message) {
222240
@TruffleBoundary
223241
public static OSErrorEnum fromNumber(int number) {
224242
OSErrorEnum[] values = values();
225-
for (int i = number; i < values.length; i++) {
243+
for (int i = 0; i < values.length; i++) {
226244
if (values[i].getNumber() == number) {
227245
return values[i];
228246
}
229247
}
230248
return null;
231249
}
250+
251+
public static ErrorAndMessagePair fromException(Exception e) {
252+
if (e instanceof IOException) {
253+
if (e instanceof NoSuchFileException || e instanceof FileNotFoundException) {
254+
return new ErrorAndMessagePair(OSErrorEnum.ENOENT, OSErrorEnum.ENOENT.getMessage());
255+
} else if (e instanceof AccessDeniedException) {
256+
return new ErrorAndMessagePair(OSErrorEnum.EACCES, OSErrorEnum.EACCES.getMessage());
257+
} else if (e instanceof FileAlreadyExistsException) {
258+
return new ErrorAndMessagePair(OSErrorEnum.EEXIST, OSErrorEnum.EEXIST.getMessage());
259+
} else if (e instanceof NotDirectoryException) {
260+
return new ErrorAndMessagePair(OSErrorEnum.ENOTDIR, OSErrorEnum.ENOTDIR.getMessage());
261+
} else if (e instanceof DirectoryNotEmptyException) {
262+
return new ErrorAndMessagePair(OSErrorEnum.ENOTEMPTY, OSErrorEnum.ENOTEMPTY.getMessage());
263+
} else if (e instanceof FileSystemLoopException) {
264+
return new ErrorAndMessagePair(OSErrorEnum.ELOOP, OSErrorEnum.ELOOP.getMessage());
265+
} else if (e instanceof NotLinkException) {
266+
return new ErrorAndMessagePair(OSErrorEnum.EINVAL, OSErrorEnum.EINVAL.getMessage());
267+
} else if (e instanceof ClosedChannelException) {
268+
return new ErrorAndMessagePair(OSErrorEnum.EPIPE, OSErrorEnum.EPIPE.getMessage());
269+
} else if (e instanceof FileSystemException) {
270+
String reason = getReason((FileSystemException) e);
271+
OSErrorEnum oserror = OSErrorEnum.fromMessage(reason);
272+
if (oserror == null) {
273+
return new ErrorAndMessagePair(OSErrorEnum.EIO, reason);
274+
} else {
275+
return new ErrorAndMessagePair(oserror, oserror.getMessage());
276+
}
277+
} else { // Generic IOException
278+
OSErrorEnum oserror = tryFindErrnoFromMessage(e);
279+
if (oserror == null) {
280+
return new ErrorAndMessagePair(OSErrorEnum.EIO, getMessage(e));
281+
} else {
282+
return new ErrorAndMessagePair(oserror, oserror.getMessage());
283+
}
284+
}
285+
} else if (e instanceof SecurityException) {
286+
return new ErrorAndMessagePair(OSErrorEnum.EPERM, OSErrorEnum.EPERM.getMessage());
287+
} else if (e instanceof IllegalArgumentException) {
288+
return new ErrorAndMessagePair(OSErrorEnum.EINVAL, OSErrorEnum.EINVAL.getMessage());
289+
} else if (e instanceof UnsupportedOperationException) {
290+
return new ErrorAndMessagePair(OSErrorEnum.EOPNOTSUPP, OSErrorEnum.EOPNOTSUPP.getMessage());
291+
} else if (e instanceof NonReadableChannelException || e instanceof NonWritableChannelException) {
292+
return new ErrorAndMessagePair(OSErrorEnum.EBADF, OSErrorEnum.EBADF.getMessage());
293+
} else if (e instanceof RuntimeException) {
294+
throw (RuntimeException) e;
295+
} else {
296+
CompilerDirectives.transferToInterpreterAndInvalidate();
297+
throw new RuntimeException(getMessage(e), e);
298+
}
299+
}
300+
301+
private static final Pattern ERRNO_PATTERN = Pattern.compile("error=(\\d+)");
302+
303+
@TruffleBoundary
304+
private static String getMessage(Exception e) {
305+
return e.getMessage();
306+
}
307+
308+
@TruffleBoundary
309+
private static String getReason(FileSystemException e) {
310+
return e.getReason();
311+
}
312+
313+
@TruffleBoundary
314+
private static OSErrorEnum tryFindErrnoFromMessage(Exception e) {
315+
Matcher m = ERRNO_PATTERN.matcher(e.getMessage());
316+
if (m.find()) {
317+
return fromNumber(Integer.parseInt(m.group(1)));
318+
}
319+
return null;
320+
}
321+
322+
@ValueType
323+
public static final class ErrorAndMessagePair {
324+
public final OSErrorEnum oserror;
325+
public final String message;
326+
327+
public ErrorAndMessagePair(OSErrorEnum oserror, String message) {
328+
this.oserror = oserror;
329+
this.message = message;
330+
}
331+
}
232332
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PBuiltinFunction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.oracle.graal.python.builtins.objects.PNone;
3636
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
3737
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
38+
import com.oracle.graal.python.builtins.objects.str.PString;
3839
import com.oracle.graal.python.builtins.objects.type.LazyPythonClass;
3940
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode;
4041
import com.oracle.graal.python.nodes.PRootNode;
@@ -77,7 +78,7 @@ public PBuiltinFunction(String name, LazyPythonClass enclosingType, int numDefau
7778
}
7879
this.getStorage().define(__NAME__, name);
7980
if (enclosingType != null) {
80-
this.getStorage().define(__QUALNAME__, GetNameNode.doSlowPath(enclosingType) + "." + name);
81+
this.getStorage().define(__QUALNAME__, PString.cat(GetNameNode.doSlowPath(enclosingType), ".", name));
8182
} else {
8283
this.getStorage().define(__QUALNAME__, name);
8384
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/PFunction.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.oracle.graal.python.builtins.objects.code.PCode;
3434
import com.oracle.graal.python.builtins.objects.object.PythonObject;
3535
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
36+
import com.oracle.graal.python.builtins.objects.str.PString;
3637
import com.oracle.graal.python.nodes.PRootNode;
3738
import com.oracle.graal.python.nodes.SpecialMethodNames;
3839
import com.oracle.graal.python.nodes.attributes.WriteAttributeToDynamicObjectNode;
@@ -92,10 +93,10 @@ public PFunction(String name, String enclosingClassName, PCode code, PythonObjec
9293
private static void addDefaultConstants(WriteAttributeToDynamicObjectNode writeAttrNode, DynamicObject storage, String name, String enclosingClassName) {
9394
if (writeAttrNode != null) {
9495
writeAttrNode.execute(storage, __NAME__, name);
95-
writeAttrNode.execute(storage, __QUALNAME__, enclosingClassName != null ? enclosingClassName + "." + name : name);
96+
writeAttrNode.execute(storage, __QUALNAME__, enclosingClassName != null ? PString.cat(enclosingClassName, ".", name) : name);
9697
} else {
9798
storage.define(__NAME__, name);
98-
storage.define(__QUALNAME__, enclosingClassName != null ? enclosingClassName + "." + name : name);
99+
storage.define(__QUALNAME__, enclosingClassName != null ? PString.cat(enclosingClassName, ".", name) : name);
99100
}
100101
}
101102

0 commit comments

Comments
 (0)