summaryrefslogtreecommitdiff
path: root/Lib/test/test_capi.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_capi.py')
-rw-r--r--Lib/test/test_capi.py129
1 files changed, 110 insertions, 19 deletions
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 36c62376b1..367feaa0b8 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -6,10 +6,12 @@ import pickle
import random
import subprocess
import sys
+import textwrap
import time
import unittest
from test import support
from test.support import MISSING_C_DOCSTRINGS
+from test.script_helper import assert_python_failure
try:
import _posixsubprocess
except ImportError:
@@ -21,6 +23,9 @@ except ImportError:
# Skip this test if the _testcapi module isn't available.
_testcapi = support.import_module('_testcapi')
+# Were we compiled --with-pydebug or with #define Py_DEBUG?
+Py_DEBUG = hasattr(sys, 'gettotalrefcount')
+
def testfunction(self):
"""some doc"""
@@ -118,7 +123,7 @@ class CAPITest(unittest.TestCase):
self.assertEqual(_testcapi.no_docstring.__doc__, None)
self.assertEqual(_testcapi.no_docstring.__text_signature__, None)
- self.assertEqual(_testcapi.docstring_empty.__doc__, "")
+ self.assertEqual(_testcapi.docstring_empty.__doc__, None)
self.assertEqual(_testcapi.docstring_empty.__text_signature__, None)
self.assertEqual(_testcapi.docstring_no_signature.__doc__,
@@ -145,11 +150,92 @@ class CAPITest(unittest.TestCase):
"This docstring has a valid signature.")
self.assertEqual(_testcapi.docstring_with_signature.__text_signature__, "($module, /, sig)")
+ self.assertEqual(_testcapi.docstring_with_signature_but_no_doc.__doc__, None)
+ self.assertEqual(_testcapi.docstring_with_signature_but_no_doc.__text_signature__,
+ "($module, /, sig)")
+
self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__doc__,
"\nThis docstring has a valid signature and some extra newlines.")
self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__text_signature__,
"($module, /, parameter)")
+ def test_c_type_with_matrix_multiplication(self):
+ M = _testcapi.matmulType
+ m1 = M()
+ m2 = M()
+ self.assertEqual(m1 @ m2, ("matmul", m1, m2))
+ self.assertEqual(m1 @ 42, ("matmul", m1, 42))
+ self.assertEqual(42 @ m1, ("matmul", 42, m1))
+ o = m1
+ o @= m2
+ self.assertEqual(o, ("imatmul", m1, m2))
+ o = m1
+ o @= 42
+ self.assertEqual(o, ("imatmul", m1, 42))
+ o = 42
+ o @= m1
+ self.assertEqual(o, ("matmul", 42, m1))
+
+ def test_return_null_without_error(self):
+ # Issue #23571: A function must not return NULL without setting an
+ # error
+ if Py_DEBUG:
+ code = textwrap.dedent("""
+ import _testcapi
+ from test import support
+
+ with support.SuppressCrashReport():
+ _testcapi.return_null_without_error()
+ """)
+ rc, out, err = assert_python_failure('-c', code)
+ self.assertRegex(err.replace(b'\r', b''),
+ br'Fatal Python error: a function returned NULL '
+ br'without setting an error\n'
+ br'SystemError: <built-in function '
+ br'return_null_without_error> returned NULL '
+ br'without setting an error\n'
+ br'\n'
+ br'Current thread.*:\n'
+ br' File .*", line 6 in <module>')
+ else:
+ with self.assertRaises(SystemError) as cm:
+ _testcapi.return_null_without_error()
+ self.assertRegex(str(cm.exception),
+ 'return_null_without_error.* '
+ 'returned NULL without setting an error')
+
+ def test_return_result_with_error(self):
+ # Issue #23571: A function must not return a result with an error set
+ if Py_DEBUG:
+ code = textwrap.dedent("""
+ import _testcapi
+ from test import support
+
+ with support.SuppressCrashReport():
+ _testcapi.return_result_with_error()
+ """)
+ rc, out, err = assert_python_failure('-c', code)
+ self.assertRegex(err.replace(b'\r', b''),
+ br'Fatal Python error: a function returned a '
+ br'result with an error set\n'
+ br'ValueError\n'
+ br'\n'
+ br'During handling of the above exception, '
+ br'another exception occurred:\n'
+ br'\n'
+ br'SystemError: <built-in '
+ br'function return_result_with_error> '
+ br'returned a result with an error set\n'
+ br'\n'
+ br'Current thread.*:\n'
+ br' File .*, line 6 in <module>')
+ else:
+ with self.assertRaises(SystemError) as cm:
+ _testcapi.return_result_with_error()
+ self.assertRegex(str(cm.exception),
+ 'return_result_with_error.* '
+ 'returned a result with an error set')
+
@unittest.skipUnless(threading, 'Threading required for this test.')
class TestPendingCalls(unittest.TestCase):
@@ -264,7 +350,7 @@ class EmbeddingTests(unittest.TestCase):
exename += ext
exepath = os.path.dirname(sys.executable)
else:
- exepath = os.path.join(basepath, "Modules")
+ exepath = os.path.join(basepath, "Programs")
self.test_exe = exe = os.path.join(exepath, exename)
if not os.path.exists(exe):
self.skipTest("%r doesn't exist" % exe)
@@ -283,12 +369,13 @@ class EmbeddingTests(unittest.TestCase):
cmd.extend(args)
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ stderr=subprocess.PIPE,
+ universal_newlines=True)
(out, err) = p.communicate()
self.assertEqual(p.returncode, 0,
"bad returncode %d, stderr is %r" %
(p.returncode, err))
- return out.decode("latin1"), err.decode("latin1")
+ return out, err
def test_subinterps(self):
# This is just a "don't crash" test
@@ -315,34 +402,38 @@ class EmbeddingTests(unittest.TestCase):
print()
print(out)
print(err)
+ expected_errors = sys.__stdout__.errors
expected_stdin_encoding = sys.__stdin__.encoding
expected_pipe_encoding = self._get_default_pipe_encoding()
- expected_output = os.linesep.join([
+ expected_output = '\n'.join([
"--- Use defaults ---",
"Expected encoding: default",
"Expected errors: default",
- "stdin: {0}:strict",
- "stdout: {1}:strict",
- "stderr: {1}:backslashreplace",
+ "stdin: {in_encoding}:{errors}",
+ "stdout: {out_encoding}:{errors}",
+ "stderr: {out_encoding}:backslashreplace",
"--- Set errors only ---",
"Expected encoding: default",
- "Expected errors: surrogateescape",
- "stdin: {0}:surrogateescape",
- "stdout: {1}:surrogateescape",
- "stderr: {1}:backslashreplace",
+ "Expected errors: ignore",
+ "stdin: {in_encoding}:ignore",
+ "stdout: {out_encoding}:ignore",
+ "stderr: {out_encoding}:backslashreplace",
"--- Set encoding only ---",
"Expected encoding: latin-1",
"Expected errors: default",
- "stdin: latin-1:strict",
- "stdout: latin-1:strict",
+ "stdin: latin-1:{errors}",
+ "stdout: latin-1:{errors}",
"stderr: latin-1:backslashreplace",
"--- Set encoding and errors ---",
"Expected encoding: latin-1",
- "Expected errors: surrogateescape",
- "stdin: latin-1:surrogateescape",
- "stdout: latin-1:surrogateescape",
- "stderr: latin-1:backslashreplace"]).format(expected_stdin_encoding,
- expected_pipe_encoding)
+ "Expected errors: replace",
+ "stdin: latin-1:replace",
+ "stdout: latin-1:replace",
+ "stderr: latin-1:backslashreplace"])
+ expected_output = expected_output.format(
+ in_encoding=expected_stdin_encoding,
+ out_encoding=expected_pipe_encoding,
+ errors=expected_errors)
# This is useful if we ever trip over odd platform behaviour
self.maxDiff = None
self.assertEqual(out.strip(), expected_output)