import os
+import sys
+import tempfile
import unittest
from collections import UserDict
+from test import support
from test.support import import_helper
from test.support.os_helper import unlink, TESTFN, TESTFN_ASCII, TESTFN_UNDECODABLE
+
NULL = None
_testcapi = import_helper.import_module('_testcapi')
Py_single_input = _testcapi.Py_single_input
Py_file_input = _testcapi.Py_file_input
Py_eval_input = _testcapi.Py_eval_input
+STDIN = '<stdin>'
+STDERR_FD = 2
+
+# Code raising a SyntaxError
+SYNTAX_ERROR = 'True = 1'
+
+# Raise a SystemExit with exit code 42
+CODE_EXIT_42 = 'raise SystemExit(42)'
+
+
+def create_text_file(filename, text):
+ with open(filename, 'w', encoding='utf8') as fp:
+ fp.write(text)
class DictSubclass(dict):
pass
-class CAPITest(unittest.TestCase):
- # TODO: Test the following functions:
- #
- # PyRun_SimpleStringFlags
- # PyRun_AnyFileExFlags
- # PyRun_SimpleFileExFlags
- # PyRun_InteractiveOneFlags
- # PyRun_InteractiveOneObject
- # PyRun_InteractiveLoopFlags
- # PyRun_String (may be a macro)
- # PyRun_AnyFile (may be a macro)
- # PyRun_AnyFileEx (may be a macro)
- # PyRun_AnyFileFlags (may be a macro)
- # PyRun_SimpleString (may be a macro)
- # PyRun_SimpleFile (may be a macro)
- # PyRun_SimpleFileEx (may be a macro)
- # PyRun_InteractiveOne (may be a macro)
- # PyRun_InteractiveLoop (may be a macro)
- # PyRun_File (may be a macro)
- # PyRun_FileEx (may be a macro)
- # PyRun_FileFlags (may be a macro)
+class capture_excepthook:
+ def __init__(self):
+ self.exc = None
+ self._old_hook = None
- def test_run_stringflags(self):
- # Test PyRun_StringFlags().
- # XXX: fopen() uses different path encoding than Python on Windows.
+ def _hook(self, exc_type, exc_value, exc_tb):
+ # Storing the exception instance creates a reference cycle.
+ self.exc = exc_value
+
+ def __enter__(self):
+ self._old_hook = sys.excepthook
+ sys.excepthook = self._hook
+ return self
+
+ def __exit__(self, *exc_info):
+ sys.excepthook = self._old_hook
+ self.exc = None
+
+
+class CAPITest(unittest.TestCase):
+ def check_run_string(self, func):
def run(s, *args):
- return _testcapi.run_stringflags(s, Py_file_input, *args)
- source = b'a\n'
+ return func(s, Py_file_input, *args)
+
+ ns = {}
+ self.assertIsNone(run(b'x = 1', ns, ns))
+ self.assertEqual(ns['x'], 1)
+
+ with self.assertRaises(SyntaxError) as cm:
+ run(SYNTAX_ERROR.encode(), {})
+ self.assertEqual(cm.exception.filename, '<string>')
+
+ with self.assertRaises(ValueError) as cm:
+ run(b'raise ValueError("BUG")', {})
+ self.assertEqual(str(cm.exception), 'BUG')
self.assertIsNone(run(b'a\n', dict(a=1)))
self.assertIsNone(run(b'a\n', dict(a=1), {}))
# CRASHES run(NULL, {})
- def test_run_fileexflags(self):
- # Test PyRun_FileExFlags().
+ def test_run_string(self):
+ # Test PyRun_String()
+ self.check_run_string(_testcapi.run_string)
+
+ def test_run_stringflags(self):
+ # Test PyRun_StringFlags().
+ self.check_run_string(_testcapi.run_stringflags)
+
+ def check_run_file(self, func, support_closeit):
+ # XXX: fopen() uses different path encoding than Python on Windows.
filename = os.fsencode(TESTFN if os.name != 'nt' else TESTFN_ASCII)
- with open(filename, 'wb') as fp:
- fp.write(b'a\n')
+ create_text_file(filename, 'a\n')
self.addCleanup(unlink, filename)
def run(*args):
- return _testcapi.run_fileexflags(filename, Py_file_input, *args)
+ return func(filename, Py_file_input, *args)
self.assertIsNone(run(dict(a=1)))
self.assertIsNone(run(dict(a=1), {}))
self.assertIsNone(run({}, dict(a=1)))
self.assertIsNone(run({}, UserDict(a=1)))
- self.assertIsNone(run(dict(a=1), {}, 1)) # closeit = True
+ if support_closeit:
+ closeit = 1
+ self.assertIsNone(run(dict(a=1), {}, closeit))
self.assertRaises(NameError, run, {})
self.assertRaises(NameError, run, {}, {})
self.assertRaises(SystemError, run, UserDict(), {})
self.assertRaises(SystemError, run, UserDict(), dict(a=1))
- @unittest.skipUnless(TESTFN_UNDECODABLE, 'only works if there are undecodable paths')
- @unittest.skipIf(os.name == 'nt', 'does not work on Windows')
- def test_run_fileexflags_with_undecodable_filename(self):
- run = _testcapi.run_fileexflags
+ # syntax error
+ create_text_file(filename, SYNTAX_ERROR)
+ with self.assertRaises(SyntaxError) as cm:
+ self.assertIsNone(run({}))
+ self.assertEqual(cm.exception.filename, os.fsdecode(filename))
+
+ # raise exception
+ create_text_file(filename, 'raise ValueError("BUG")')
+ with self.assertRaises(ValueError) as cm:
+ self.assertIsNone(run({}))
+ self.assertEqual(str(cm.exception), 'BUG')
+
+ # Test undecodable filename
+ if TESTFN_UNDECODABLE and os.name != 'nt':
+ try:
+ create_text_file(TESTFN_UNDECODABLE, 'a\n')
+ self.addCleanup(unlink, TESTFN_UNDECODABLE)
+ except OSError:
+ # undecodable paths are not supported
+ pass
+ else:
+ self.assertIsNone(func(TESTFN_UNDECODABLE, Py_file_input, dict(a=1)))
+
+ def test_run_file(self):
+ # Test PyRun_File().
+ self.check_run_file(_testcapi.run_file, False)
+
+ def test_run_fileex(self):
+ # Test PyRun_FileEx().
+ self.check_run_file(_testcapi.run_fileex, True)
+
+ def test_run_fileflags(self):
+ # Test PyRun_FileFlags().
+ self.check_run_file(_testcapi.run_fileflags, True)
+
+ def test_run_fileexflags(self):
+ # Test PyRun_FileExFlags().
+ self.check_run_file(_testcapi.run_fileexflags, True)
+
+ def check_run_simplefile(self, func_name, have_closeit):
+ run = getattr(_testcapi, func_name)
+
+ open_filename = TESTFN
+ with open(open_filename, 'w') as fp:
+ print('import sys', file=fp)
+ print('print(__file__)', file=fp)
+ print('mod = sys.modules["__main__"]', file=fp)
+ print('print(type(mod.__loader__).__name__)', file=fp)
+ self.addCleanup(unlink, open_filename)
+
+ class MockLoader:
+ pass
+ loader = MockLoader()
+
+ for closeit in (0, 1):
+ for set_file in (False, True):
+ for filename in (open_filename, 'custom filename', STDIN):
+ set_loader = (filename != STDIN)
+ with self.subTest(closeit=closeit,
+ set_file=set_file,
+ filename=filename):
+ mod = sys.modules['__main__']
+ mod_file = mod.__file__
+ with (support.captured_stdout() as stdout,
+ support.swap_attr(mod, '__loader__', loader)):
+ try:
+ if set_file:
+ del mod.__file__
+ filename_arg = os.fsencode(filename)
+ if have_closeit:
+ res = run(open_filename, filename_arg, closeit)
+ else:
+ res = run(open_filename, filename_arg)
+ if set_file:
+ self.assertFalse(hasattr(mod, '__file__'))
+ finally:
+ mod.__file__ = mod_file
+
+ self.assertEqual(res, 0)
+ expected = [filename if set_file else mod_file]
+ if set_loader:
+ expected.append('SourceFileLoader')
+ else:
+ expected.append('MockLoader')
+ self.assertEqual(stdout.getvalue().splitlines(),
+ expected)
+
+ def test_run_simplefile(self):
+ # Test PyRun_SimpleFile()
+ self.check_run_simplefile('run_simplefile', False)
+
+ def test_run_simplefileex(self):
+ # Test PyRun_SimpleFileEx()
+ self.check_run_simplefile('run_simplefileex', True)
+
+ def test_run_simplefileexflags(self):
+ # Test PyRun_SimpleFileExFlags()
+ self.check_run_simplefile('run_simplefileexflags', True)
+
+ def test_run_anyfile(self):
+ # Test PyRun_AnyFile()
+ self.check_run_simplefile('run_anyfile', False)
+
+ def test_run_anyfileex(self):
+ # Test PyRun_AnyFileEx()
+ self.check_run_simplefile('run_anyfileex', True)
+
+ def test_run_anyfileflags(self):
+ # Test PyRun_AnyFileFlags()
+ self.check_run_simplefile('run_anyfileflags', True)
+
+ def _check_run_interactive(self, run, encode_filename, use_loop):
+ open_filename = TESTFN
+ if use_loop:
+ with open(open_filename, 'w') as fp:
+ print('welcome = "hello REPL"', file=fp)
+ print('print(welcome)', file=fp)
+ else:
+ create_text_file(open_filename, 'print("hello REPL")')
+ self.addCleanup(unlink, open_filename)
+
+ for filename in ('filename', STDIN):
+ with self.subTest(filename=filename):
+ with support.captured_stdout() as stdout:
+ if encode_filename:
+ filename = filename.encode()
+ self.assertEqual(run(open_filename, filename), 0)
+ self.assertEqual(stdout.getvalue(), 'hello REPL\n')
+
+ create_text_file(open_filename, SYNTAX_ERROR)
+ filename = 'custom filename'
+ if encode_filename:
+ filename_arg = filename.encode()
+ else:
+ filename_arg = filename
+ with capture_excepthook() as excepthook:
+ expected = (0 if use_loop else -1)
+ self.assertEqual(run(open_filename, filename_arg), expected)
+ self.assertIsInstance(excepthook.exc, SyntaxError)
+ self.assertEqual(excepthook.exc.filename, filename)
+
+ create_text_file(open_filename, 'raise ValueError("BUG")')
+ with capture_excepthook() as excepthook:
+ expected = (0 if use_loop else -1)
+ self.assertEqual(run(open_filename, filename_arg), expected)
+ self.assertIsInstance(excepthook.exc, ValueError)
+ self.assertEqual(str(excepthook.exc), 'BUG')
+
+ if not encode_filename:
+ # wrong type for the second parameter (filename)
+ with capture_excepthook() as excepthook:
+ self.assertEqual(run(open_filename, b'bytes'), -1)
+ self.assertIsInstance(excepthook.exc, TypeError)
+
+ def check_run_interactive(self, run, encode_filename, use_loop=False):
+ # Redirect stderr to a temporary file to hide '>>> ' from the REPL
try:
- with open(TESTFN_UNDECODABLE, 'wb') as fp:
- fp.write(b'a\n')
- self.addCleanup(unlink, TESTFN_UNDECODABLE)
+ stderr_copy = os.dup(STDERR_FD)
except OSError:
- self.skipTest('undecodable paths are not supported')
- self.assertIsNone(run(TESTFN_UNDECODABLE, Py_file_input, dict(a=1)))
+ # On WASI, dup(STDERR_FD) fails with "OSError: [Errno 58] Not
+ # supported". In this case, run the test without redirecting
+ # stderr to a temporary file.
+ self._check_run_interactive(run, encode_filename, use_loop)
+ else:
+ with tempfile.TemporaryFile() as tmp:
+ try:
+ os.dup2(tmp.fileno(), STDERR_FD)
+ self._check_run_interactive(run, encode_filename, use_loop)
+ finally:
+ os.dup2(stderr_copy, STDERR_FD)
+
+ def test_run_interactiveone(self):
+ # Test PyRun_InteractiveOne()
+ run = _testcapi.run_interactiveone
+ self.check_run_interactive(run, True)
+
+ def test_run_interactiveoneflags(self):
+ # Test PyRun_InteractiveOneFlags()
+ run = _testcapi.run_interactiveoneflags
+ self.check_run_interactive(run, True)
+
+ def test_run_interactiveoneobject(self):
+ # Test PyRun_InteractiveOneObject()
+ run = _testcapi.run_interactiveoneobject
+ self.check_run_interactive(run, False)
+
+ def test_run_interactiveloop(self):
+ # Test PyRun_InteractiveLoop()
+ run = _testcapi.run_interactiveloop
+ self.check_run_interactive(run, True, use_loop=True)
+
+ def test_run_interactiveloopflags(self):
+ # Test PyRun_InteractiveLoopFlags()
+ run = _testcapi.run_interactiveloopflags
+ self.check_run_interactive(run, True, use_loop=True)
+
+ def test_run_anyfileexflags(self):
+ # Test PyRun_AnyFileExFlags()
+ self.check_run_simplefile('run_anyfileexflags', True)
+
+ def check_run_simplestring(self, run):
+ with support.captured_stdout() as stdout:
+ run(b'print("simple hello")')
+ self.assertEqual(stdout.getvalue(), 'simple hello\n')
+
+ with capture_excepthook() as excepthook:
+ self.assertEqual(run(SYNTAX_ERROR.encode()), -1)
+ self.assertIsInstance(excepthook.exc, SyntaxError)
+ self.assertEqual(excepthook.exc.filename, '<string>')
+
+ with capture_excepthook() as excepthook:
+ self.assertEqual(run(b'raise ValueError("BUG")'), -1)
+ self.assertIsInstance(excepthook.exc, ValueError)
+ self.assertEqual(str(excepthook.exc), 'BUG')
+
+ def test_run_simplestring(self):
+ # Test PyRun_SimpleString()
+ self.check_run_simplestring(_testcapi.run_simplestring)
+
+ def test_run_simplestringflags(self):
+ # Test PyRun_SimpleStringFlags()
+ self.check_run_simplestring(_testcapi.run_simplestringflags)
if __name__ == '__main__':
#include <errno.h>
-static PyObject *
-run_stringflags(PyObject *mod, PyObject *pos_args)
+// Test functions, not macros
+#undef PyRun_AnyFile
+#undef PyRun_AnyFileEx
+#undef PyRun_AnyFileFlags
+#undef PyRun_File
+#undef PyRun_FileEx
+#undef PyRun_FileFlags
+#undef PyRun_SimpleFile
+#undef PyRun_SimpleFileEx
+#undef PyRun_String
+#undef PyRun_SimpleString
+#undef Py_CompileString
+#undef Py_CompileStringFlags
+#undef PyRun_InteractiveOne
+#undef PyRun_InteractiveLoop
+
+
+// Some PyRun functions crash if start is invalid,
+// so validate the start argument.
+static int
+check_start(int start)
+{
+ if (start == Py_single_input || start == Py_file_input
+ || start == Py_eval_input || start == Py_func_type_input)
+ {
+ return 0;
+ }
+ PyErr_SetString(PyExc_ValueError, "invalid start argument");
+ return -1;
+}
+
+
+// Test PyRun_String()
+static PyObject*
+run_string(PyObject *mod, PyObject *args)
+{
+ const char *str;
+ int start = 0;
+ PyObject *globals = NULL;
+ PyObject *locals = NULL;
+
+ if (!PyArg_ParseTuple(args, "y|iOO", &str, &start, &globals, &locals)) {
+ return NULL;
+ }
+ if (check_start(start) < 0) {
+ return NULL;
+ }
+ NULLABLE(globals);
+ NULLABLE(locals);
+
+ return PyRun_String(str, start, globals, locals);
+}
+
+// Test PyRun_StringFlags()
+static PyObject*
+run_stringflags(PyObject *mod, PyObject *args)
{
const char *str;
Py_ssize_t size;
int cf_flags = 0;
int cf_feature_version = 0;
- if (!PyArg_ParseTuple(pos_args, "z#iO|Oii",
+ if (!PyArg_ParseTuple(args, "z#iO|Oii",
&str, &size, &start, &globals, &locals,
&cf_flags, &cf_feature_version)) {
return NULL;
}
-
+ if (check_start(start) < 0) {
+ return NULL;
+ }
NULLABLE(globals);
NULLABLE(locals);
if (cf_flags || cf_feature_version) {
return PyRun_StringFlags(str, start, globals, locals, pflags);
}
-static PyObject *
-run_fileexflags(PyObject *mod, PyObject *pos_args)
+static FILE*
+open_file(PyObject *filename, int *closeit)
+{
+ if (PyUnicode_EqualToUTF8(filename, "<stdin>")) {
+ if (closeit) {
+ // override closeit
+ *closeit = 0;
+ }
+ return stdin;
+ }
+ return Py_fopen(filename, "r");
+}
+
+
+// Test PyRun_SimpleFile()
+static PyObject*
+run_simplefile(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ const char *filename;
+
+ if (!PyArg_ParseTuple(args, "Oy", &open_filename, &filename)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, NULL);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ int res = PyRun_SimpleFile(fp, filename);
+
+ assert(_Py_IsValidFD(fd));
+ fclose(fp);
+
+ if (res == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ assert(!PyErr_Occurred());
+ return PyLong_FromLong(res);
+}
+
+static int
+close_fd(FILE *fp, int fd, int closeit)
+{
+ if (closeit && _Py_IsValidFD(fd)) {
+ PyErr_SetString(PyExc_AssertionError, "File was not closed after execution");
+ fclose(fp);
+ return -1;
+ }
+
+ if (!closeit && !_Py_IsValidFD(fd)) {
+ PyErr_SetString(PyExc_AssertionError, "Bad file descriptor after execution");
+ return -1;
+ }
+
+ if (!closeit) {
+ fclose(fp);
+ }
+ return 0;
+}
+
+static int
+close_fd_result(FILE *fp, int fd, int closeit, PyObject *result)
+{
+ if (closeit && result && _Py_IsValidFD(fd)) {
+ PyErr_SetString(PyExc_AssertionError, "File was not closed after execution");
+ Py_DECREF(result);
+ fclose(fp);
+ return -1;
+ }
+
+ if (!closeit && !_Py_IsValidFD(fd)) {
+ PyErr_SetString(PyExc_AssertionError, "Bad file descriptor after execution");
+ Py_XDECREF(result);
+ return -1;
+ }
+
+ if (!closeit) {
+ fclose(fp);
+ }
+ return 0;
+}
+
+// Test PyRun_SimpleFileEx()
+static PyObject*
+run_simplefileex(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ const char *filename;
+ int closeit = 0;
+
+ if (!PyArg_ParseTuple(args, "Oy|i",
+ &open_filename, &filename, &closeit)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, &closeit);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ int res = PyRun_SimpleFileEx(fp, filename, closeit);
+
+ if (close_fd(fp, fd, closeit) < 0) {
+ return NULL;
+ }
+
+ if (res == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ assert(!PyErr_Occurred());
+ return PyLong_FromLong(res);
+}
+
+// Test PyRun_SimpleFileExFlags()
+static PyObject*
+run_simplefileexflags(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ const char *filename;
+ int closeit = 0;
+ PyCompilerFlags flags = _PyCompilerFlags_INIT;
+ PyCompilerFlags *pflags = NULL;
+ int cf_flags = 0;
+
+ if (!PyArg_ParseTuple(args, "Oy|ii",
+ &open_filename, &filename, &closeit, &cf_flags)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, &closeit);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ if (cf_flags) {
+ flags.cf_flags = cf_flags;
+ pflags = &flags;
+ }
+
+ int res = PyRun_SimpleFileExFlags(fp, filename, closeit, pflags);
+
+ if (close_fd(fp, fd, closeit) < 0) {
+ return NULL;
+ }
+
+ if (res == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ assert(!PyErr_Occurred());
+ return PyLong_FromLong(res);
+}
+
+// Test PyRun_AnyFile()
+static PyObject*
+run_anyfile(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ const char *filename;
+
+ if (!PyArg_ParseTuple(args, "Oy", &open_filename, &filename)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, NULL);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ int res = PyRun_AnyFile(fp, filename);
+
+ assert(_Py_IsValidFD(fd));
+ fclose(fp);
+
+ if (res == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ assert(!PyErr_Occurred());
+ return PyLong_FromLong(res);
+}
+
+// Test PyRun_AnyFileFlags()
+static PyObject*
+run_anyfileflags(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ const char *filename;
+ PyCompilerFlags flags = _PyCompilerFlags_INIT;
+ PyCompilerFlags *pflags = NULL;
+ int cf_flags = 0;
+
+ if (!PyArg_ParseTuple(args, "Oy|i",
+ &open_filename, &filename, &cf_flags)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, NULL);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ if (cf_flags) {
+ flags.cf_flags = cf_flags;
+ pflags = &flags;
+ }
+
+ int res = PyRun_AnyFileFlags(fp, filename, pflags);
+
+ assert(_Py_IsValidFD(fd));
+ fclose(fp);
+
+ if (res == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ assert(!PyErr_Occurred());
+ return PyLong_FromLong(res);
+}
+
+// Test PyRun_AnyFileEx()
+static PyObject*
+run_anyfileex(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ const char *filename;
+ int closeit = 0;
+
+ if (!PyArg_ParseTuple(args, "Oy|i",
+ &open_filename, &filename, &closeit)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, &closeit);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ int res = PyRun_AnyFileEx(fp, filename, closeit);
+
+ if (close_fd(fp, fd, closeit) < 0) {
+ return NULL;
+ }
+
+ if (res == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ assert(!PyErr_Occurred());
+ return PyLong_FromLong(res);
+}
+
+// Test PyRun_AnyFileExFlags()
+static PyObject*
+run_anyfileexflags(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ const char *filename;
+ int closeit = 0;
+ PyCompilerFlags flags = _PyCompilerFlags_INIT;
+ PyCompilerFlags *pflags = NULL;
+ int cf_flags = 0;
+
+ if (!PyArg_ParseTuple(args, "Oy|ii",
+ &open_filename, &filename, &closeit, &cf_flags)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, &closeit);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ if (cf_flags) {
+ flags.cf_flags = cf_flags;
+ pflags = &flags;
+ }
+
+ int res = PyRun_AnyFileExFlags(fp, filename, closeit, pflags);
+
+ if (close_fd(fp, fd, closeit) < 0) {
+ return NULL;
+ }
+
+ if (res == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ assert(!PyErr_Occurred());
+ return PyLong_FromLong(res);
+}
+
+
+// Test PyRun_InteractiveOne()
+static PyObject*
+run_interactiveone(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ char *filename;
+
+ if (!PyArg_ParseTuple(args, "Oy", &open_filename, &filename)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, NULL);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ int res = PyRun_InteractiveOne(fp, filename);
+ assert(!PyErr_Occurred());
+
+ assert(_Py_IsValidFD(fd));
+ fclose(fp);
+
+ return PyLong_FromLong(res);
+}
+
+// Test PyRun_InteractiveOneFlags()
+static PyObject*
+run_interactiveoneflags(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ char *filename;
+ PyCompilerFlags flags = _PyCompilerFlags_INIT;
+ PyCompilerFlags *pflags = NULL;
+ int cf_flags = 0;
+
+ if (!PyArg_ParseTuple(args, "Oy|i",
+ &open_filename, &filename, &cf_flags)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, NULL);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ if (cf_flags) {
+ flags.cf_flags = cf_flags;
+ pflags = &flags;
+ }
+
+ int res = PyRun_InteractiveOneFlags(fp, filename, pflags);
+ assert(!PyErr_Occurred());
+
+ assert(_Py_IsValidFD(fd));
+ fclose(fp);
+
+ return PyLong_FromLong(res);
+}
+
+// Test PyRun_InteractiveOneObject()
+static PyObject*
+run_interactiveoneobject(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ PyObject *filename;
+ PyCompilerFlags flags = _PyCompilerFlags_INIT;
+ PyCompilerFlags *pflags = NULL;
+ int cf_flags = 0;
+
+ if (!PyArg_ParseTuple(args, "OO|i",
+ &open_filename, &filename, &cf_flags)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, NULL);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ if (cf_flags) {
+ flags.cf_flags = cf_flags;
+ pflags = &flags;
+ }
+
+ int res = PyRun_InteractiveOneObject(fp, filename, pflags);
+ assert(!PyErr_Occurred());
+
+ assert(_Py_IsValidFD(fd));
+ fclose(fp);
+
+ return PyLong_FromLong(res);
+}
+
+// Test PyRun_File()
+static PyObject*
+run_file(PyObject *mod, PyObject *args)
{
PyObject *result = NULL;
const char *filename = NULL;
int start;
PyObject *globals = NULL;
PyObject *locals = NULL;
+
+ if (!PyArg_ParseTuple(args, "z#iO|O",
+ &filename, &filename_size, &start,
+ &globals, &locals)) {
+ return NULL;
+ }
+ if (check_start(start) < 0) {
+ return NULL;
+ }
+ NULLABLE(globals);
+ NULLABLE(locals);
+
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ result = PyRun_File(fp, filename, start, globals, locals);
+
+ assert(_Py_IsValidFD(fd));
+ fclose(fp);
+
+ return result;
+}
+
+// Test PyRun_FileEx()
+static PyObject*
+run_fileex(PyObject *mod, PyObject *args)
+{
+ const char *filename = NULL;
+ Py_ssize_t filename_size;
+ int start;
+ PyObject *globals = NULL;
+ PyObject *locals = NULL;
int closeit = 0;
+
+ if (!PyArg_ParseTuple(args, "z#iO|Oi",
+ &filename, &filename_size, &start, &globals, &locals,
+ &closeit)) {
+ return NULL;
+ }
+ if (check_start(start) < 0) {
+ return NULL;
+ }
+ NULLABLE(globals);
+ NULLABLE(locals);
+
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ PyObject *result = PyRun_FileEx(fp, filename, start, globals, locals,
+ closeit);
+
+ if (close_fd_result(fp, fd, closeit, result) < 0) {
+ return NULL;
+ }
+
+ return result;
+}
+
+// Test PyRun_FileFlags
+static PyObject*
+run_fileflags(PyObject *mod, PyObject *args)
+{
+ const char *filename = NULL;
+ Py_ssize_t filename_size;
+ int start;
+ PyObject *globals = NULL;
+ PyObject *locals = NULL;
PyCompilerFlags flags = _PyCompilerFlags_INIT;
PyCompilerFlags *pflags = NULL;
int cf_flags = 0;
int cf_feature_version = 0;
- FILE *fp = NULL;
+ if (!PyArg_ParseTuple(args, "z#iO|Oii",
+ &filename, &filename_size, &start, &globals, &locals,
+ &cf_flags, &cf_feature_version)) {
+ return NULL;
+ }
+ if (check_start(start) < 0) {
+ return NULL;
+ }
+ NULLABLE(globals);
+ NULLABLE(locals);
+ if (cf_flags || cf_feature_version) {
+ flags.cf_flags = cf_flags;
+ flags.cf_feature_version = cf_feature_version;
+ pflags = &flags;
+ }
+
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ PyObject *result = PyRun_FileFlags(fp, filename, start, globals, locals,
+ pflags);
+
+ assert(_Py_IsValidFD(fd));
+ fclose(fp);
+
+ return result;
+}
+
+static PyObject*
+run_fileexflags(PyObject *mod, PyObject *args)
+{
+ const char *filename = NULL;
+ Py_ssize_t filename_size;
+ int start;
+ PyObject *globals = NULL;
+ PyObject *locals = NULL;
+ int closeit = 0;
+ PyCompilerFlags flags = _PyCompilerFlags_INIT;
+ PyCompilerFlags *pflags = NULL;
+ int cf_flags = 0;
+ int cf_feature_version = 0;
- if (!PyArg_ParseTuple(pos_args, "z#iO|Oiii",
+ if (!PyArg_ParseTuple(args, "z#iO|Oiii",
&filename, &filename_size, &start, &globals, &locals,
&closeit, &cf_flags, &cf_feature_version)) {
return NULL;
}
-
+ if (check_start(start) < 0) {
+ return NULL;
+ }
NULLABLE(globals);
NULLABLE(locals);
if (cf_flags || cf_feature_version) {
pflags = &flags;
}
- fp = fopen(filename, "r");
+ FILE *fp = fopen(filename, "r");
if (fp == NULL) {
PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
return NULL;
}
int fd = fileno(fp);
- result = PyRun_FileExFlags(fp, filename, start, globals, locals, closeit, pflags);
+ PyObject *result = PyRun_FileExFlags(fp, filename, start, globals, locals,
+ closeit, pflags);
- if (closeit && result && _Py_IsValidFD(fd)) {
- PyErr_SetString(PyExc_AssertionError, "File was not closed after execution");
- Py_DECREF(result);
- fclose(fp);
+ if (close_fd_result(fp, fd, closeit, result) < 0) {
return NULL;
}
- if (!closeit && !_Py_IsValidFD(fd)) {
- PyErr_SetString(PyExc_AssertionError, "Bad file descriptor after execution");
- Py_XDECREF(result);
+ return result;
+}
+
+static PyObject*
+run_simplestring(PyObject *mod, PyObject *args)
+{
+ const char *str;
+ if (!PyArg_ParseTuple(args, "y", &str)) {
return NULL;
}
- if (!closeit) {
- fclose(fp); /* don't need open file any more*/
+ int res = PyRun_SimpleString(str);
+ if (res == -1 && PyErr_Occurred()) {
+ return NULL;
}
+ assert(!PyErr_Occurred());
+ return PyLong_FromLong(res);
+}
- return result;
+static PyObject*
+run_simplestringflags(PyObject *mod, PyObject *args)
+{
+ const char *str;
+ PyCompilerFlags flags = _PyCompilerFlags_INIT;
+ PyCompilerFlags *pflags = NULL;
+ int cf_flags = 0;
+
+ if (!PyArg_ParseTuple(args, "y|i", &str, &flags)) {
+ return NULL;
+ }
+
+ if (cf_flags) {
+ flags.cf_flags = cf_flags;
+ pflags = &flags;
+ }
+
+ int res = PyRun_SimpleStringFlags(str, pflags);
+ if (res == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ assert(!PyErr_Occurred());
+ return PyLong_FromLong(res);
}
+
+// Test PyRun_InteractiveLoop()
+static PyObject*
+run_interactiveloop(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ char *filename;
+
+ if (!PyArg_ParseTuple(args, "Oy|i", &open_filename, &filename)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, NULL);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ int res = PyRun_InteractiveLoop(fp, filename);
+ assert(!PyErr_Occurred());
+
+ assert(_Py_IsValidFD(fd));
+ fclose(fp);
+
+ return PyLong_FromLong(res);
+}
+
+
+// Test PyRun_InteractiveLoopFlags()
+static PyObject*
+run_interactiveloopflags(PyObject *mod, PyObject *args)
+{
+ PyObject *open_filename;
+ char *filename;
+ PyCompilerFlags flags = _PyCompilerFlags_INIT;
+ PyCompilerFlags *pflags = NULL;
+ int cf_flags = 0;
+
+ if (!PyArg_ParseTuple(args, "Oy|i",
+ &open_filename, &filename, &cf_flags)) {
+ return NULL;
+ }
+
+ FILE *fp = open_file(open_filename, NULL);
+ if (fp == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fp);
+
+ if (cf_flags) {
+ flags.cf_flags = cf_flags;
+ pflags = &flags;
+ }
+
+ int res = PyRun_InteractiveLoopFlags(fp, filename, pflags);
+ assert(!PyErr_Occurred());
+
+ assert(_Py_IsValidFD(fd));
+ fclose(fp);
+
+ return PyLong_FromLong(res);
+}
+
+
static PyMethodDef test_methods[] = {
+ {"run_string", run_string, METH_VARARGS},
{"run_stringflags", run_stringflags, METH_VARARGS},
+ {"run_simplefile", run_simplefile, METH_VARARGS},
+ {"run_simplefileex", run_simplefileex, METH_VARARGS},
+ {"run_simplefileexflags", run_simplefileexflags, METH_VARARGS},
+ {"run_anyfile", run_anyfile, METH_VARARGS},
+ {"run_anyfileflags", run_anyfileflags, METH_VARARGS},
+ {"run_anyfileex", run_anyfileex, METH_VARARGS},
+ {"run_anyfileexflags", run_anyfileexflags, METH_VARARGS},
+ {"run_interactiveone", run_interactiveone, METH_VARARGS},
+ {"run_interactiveoneflags", run_interactiveoneflags, METH_VARARGS},
+ {"run_interactiveoneobject", run_interactiveoneobject, METH_VARARGS},
+ {"run_file", run_file, METH_VARARGS},
+ {"run_fileex", run_fileex, METH_VARARGS},
+ {"run_fileflags", run_fileflags, METH_VARARGS},
{"run_fileexflags", run_fileexflags, METH_VARARGS},
+ {"run_simplestring", run_simplestring, METH_VARARGS},
+ {"run_simplestringflags", run_simplestringflags, METH_VARARGS},
+ {"run_interactiveloop", run_interactiveloop, METH_VARARGS},
+ {"run_interactiveloopflags", run_interactiveloopflags, METH_VARARGS},
{NULL},
};