Skip to content

Commit 6edc82c

Browse files
Move helpers to _testlimitedcapi and assert error messages
The PyCapsule C API is part of the limited C API. Also assert the messages of the ImportError raised by PyCapsule_Import() and fix the check_import() helper after applying the review suggestion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 9d43cee commit 6edc82c

11 files changed

Lines changed: 51 additions & 41 deletions

File tree

Lib/test/test_capi/test_capsule.py

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import unittest
66
from test.support import import_helper, os_helper
77

8-
_testcapi = import_helper.import_module('_testcapi')
8+
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')
99

1010

1111
class CapsuleImportTests(unittest.TestCase):
@@ -16,17 +16,17 @@ def setUpClass(cls):
1616
tmp = cls.tmp = cls.enterClassContext(os_helper.temp_dir())
1717
cls.enterClassContext(import_helper.DirsOnSysPath(tmp))
1818
cls.write_file(os.path.join(tmp, 'capsule_mod.py'), '''
19-
import _testcapi
19+
import _testlimitedcapi
2020
21-
capsule = _testcapi.capsule_new('capsule_mod.capsule')
22-
капсула = _testcapi.capsule_new('capsule_mod.капсула')
23-
mismatched = _testcapi.capsule_new('other.name')
24-
nonutf8 = _testcapi.capsule_new(b'capsule_mod.nonutf8\\xff')
25-
nullname = _testcapi.capsule_new(None)
21+
capsule = _testlimitedcapi.capsule_new('capsule_mod.capsule')
22+
капсула = _testlimitedcapi.capsule_new('capsule_mod.капсула')
23+
mismatched = _testlimitedcapi.capsule_new('other.name')
24+
nonutf8 = _testlimitedcapi.capsule_new(b'capsule_mod.nonutf8\\xff')
25+
nullname = _testlimitedcapi.capsule_new(None)
2626
not_capsule = 42
2727
2828
class ns:
29-
nested = _testcapi.capsule_new('capsule_mod.ns.nested')
29+
nested = _testlimitedcapi.capsule_new('capsule_mod.ns.nested')
3030
3131
def __getattr__(name):
3232
if name == 'bad_attr':
@@ -37,17 +37,17 @@ def __getattr__(name):
3737
os.mkdir(pkg)
3838
cls.write_file(os.path.join(pkg, '__init__.py'), '')
3939
cls.write_file(os.path.join(pkg, 'sub.py'), '''
40-
import _testcapi
40+
import _testlimitedcapi
4141
42-
capsule = _testcapi.capsule_new('capsule_pkg.sub.capsule')
42+
capsule = _testlimitedcapi.capsule_new('capsule_pkg.sub.capsule')
4343
''')
4444
autopkg = os.path.join(tmp, 'capsule_autopkg')
4545
os.mkdir(autopkg)
4646
cls.write_file(os.path.join(autopkg, '__init__.py'), 'from . import sub\n')
4747
cls.write_file(os.path.join(autopkg, 'sub.py'), '''
48-
import _testcapi
48+
import _testlimitedcapi
4949
50-
capsule = _testcapi.capsule_new('capsule_autopkg.sub.capsule')
50+
capsule = _testlimitedcapi.capsule_new('capsule_autopkg.sub.capsule')
5151
''')
5252
cls.write_file(os.path.join(tmp, 'capsule_broken.py'), '1/0\n')
5353
importlib.invalidate_caches()
@@ -64,9 +64,9 @@ def write_file(path, source):
6464
f.write(textwrap.dedent(source))
6565

6666
def check_import(self, name, no_block=0):
67-
# _testcapi.PyCapsule_Import() returns the name stored as the
68-
# pointer by _testcapi.capsule_new().
69-
self.assertEqual(_testcapi.PyCapsule_Import(name, *args), name)
67+
# _testlimitedcapi.PyCapsule_Import() returns the name stored as the
68+
# pointer by _testlimitedcapi.capsule_new().
69+
self.assertEqual(_testlimitedcapi.PyCapsule_Import(name, no_block), name)
7070

7171
def test_import(self):
7272
# The module is imported if not already imported.
@@ -84,9 +84,9 @@ def test_import(self):
8484
def test_non_ascii_module_name(self):
8585
name = os_helper.TESTFN_NONASCII
8686
self.write_file(os.path.join(self.tmp, name + '.py'), f'''
87-
import _testcapi
87+
import _testlimitedcapi
8888
89-
capsule = _testcapi.capsule_new('{name}.capsule')
89+
capsule = _testlimitedcapi.capsule_new('{name}.capsule')
9090
''')
9191
importlib.invalidate_caches()
9292
self.addCleanup(import_helper.unload, name)
@@ -96,26 +96,35 @@ def test_submodule(self):
9696
# Only the first component is imported; a submodule not imported
9797
# by its package is not found.
9898
self.assertRaises(AttributeError,
99-
_testcapi.PyCapsule_Import, 'capsule_pkg.sub.capsule')
99+
_testlimitedcapi.PyCapsule_Import, 'capsule_pkg.sub.capsule')
100100
# It is found after explicit import.
101101
importlib.import_module('capsule_pkg.sub')
102102
self.check_import('capsule_pkg.sub.capsule')
103103
# A submodule imported by its package is found.
104104
self.check_import('capsule_autopkg.sub.capsule')
105105

106106
def test_invalid_name(self):
107-
pycapsule_import = _testcapi.PyCapsule_Import
107+
pycapsule_import = _testlimitedcapi.PyCapsule_Import
108108
# Non-existing module.
109-
self.assertRaises(ImportError,
110-
pycapsule_import, 'capsule_nonexistent.capsule')
109+
self.assertRaisesRegex(ImportError,
110+
'PyCapsule_Import could not import module "capsule_nonexistent"',
111+
pycapsule_import, 'capsule_nonexistent.capsule')
111112
# Non-UTF-8 module name.
112-
self.assertRaises(ImportError, pycapsule_import, b'\xff\xfe.capsule')
113+
self.assertRaisesRegex(ImportError,
114+
'PyCapsule_Import could not import module',
115+
pycapsule_import, b'\xff\xfe.capsule')
113116
# Empty module name.
114-
self.assertRaises(ImportError, pycapsule_import, '.capsule_mod.capsule')
117+
self.assertRaisesRegex(ImportError,
118+
'PyCapsule_Import could not import module ""',
119+
pycapsule_import, '.capsule_mod.capsule')
115120
# Empty name.
116-
self.assertRaises(ImportError, pycapsule_import, '')
121+
self.assertRaisesRegex(ImportError,
122+
'PyCapsule_Import could not import module ""',
123+
pycapsule_import, '')
117124
# Only a dot.
118-
self.assertRaises(ImportError, pycapsule_import, '.')
125+
self.assertRaisesRegex(ImportError,
126+
'PyCapsule_Import could not import module ""',
127+
pycapsule_import, '.')
119128
# Non-existing attribute.
120129
self.assertRaises(AttributeError,
121130
pycapsule_import, 'capsule_mod.nonexistent')
@@ -134,7 +143,7 @@ def test_invalid_name(self):
134143
# CRASHES pycapsule_import(NULL)
135144

136145
def test_invalid_capsule(self):
137-
pycapsule_import = _testcapi.PyCapsule_Import
146+
pycapsule_import = _testlimitedcapi.PyCapsule_Import
138147
# The attribute is not a capsule.
139148
self.assertRaisesRegex(AttributeError, 'is not valid',
140149
pycapsule_import, 'capsule_mod.not_capsule')
@@ -155,14 +164,17 @@ def test_invalid_capsule(self):
155164
def test_error_from_import(self):
156165
# The exception raised during importing the module is replaced
157166
# with generic ImportError.
158-
self.assertRaises(ImportError,
159-
_testcapi.PyCapsule_Import, 'capsule_broken.capsule')
167+
with self.assertRaises(ImportError) as cm:
168+
_testlimitedcapi.PyCapsule_Import('capsule_broken.capsule')
169+
self.assertEqual(str(cm.exception),
170+
'PyCapsule_Import could not import '
171+
'module "capsule_broken"')
160172

161173
def test_error_from_attribute_lookup(self):
162174
self.assertRaises(FloatingPointError,
163-
_testcapi.PyCapsule_Import, 'capsule_mod.bad_attr')
175+
_testlimitedcapi.PyCapsule_Import, 'capsule_mod.bad_attr')
164176
self.assertRaises(FloatingPointError,
165-
_testcapi.PyCapsule_Import, 'capsule_mod.bad_attr.capsule')
177+
_testlimitedcapi.PyCapsule_Import, 'capsule_mod.bad_attr.capsule')
166178

167179

168180
if __name__ == "__main__":

Modules/Setup.stdlib.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@
173173
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
174174
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
175175
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c _testinternalcapi/complex.c _testinternalcapi/interpreter.c _testinternalcapi/tuple.c _testinternalcapi/typecache.c
176-
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/capsule.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c
177-
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c _testlimitedcapi/run.c
176+
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c
177+
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/capsule.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c _testlimitedcapi/run.c
178178
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
179179
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
180180

Modules/_testcapi/parts.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ int _PyTestCapi_Init_Monitoring(PyObject *module);
6363
int _PyTestCapi_Init_Object(PyObject *module);
6464
int _PyTestCapi_Init_Config(PyObject *mod);
6565
int _PyTestCapi_Init_Import(PyObject *mod);
66-
int _PyTestCapi_Init_Capsule(PyObject *mod);
6766
int _PyTestCapi_Init_Frame(PyObject *mod);
6867
int _PyTestCapi_Init_Type(PyObject *mod);
6968
int _PyTestCapi_Init_Function(PyObject *mod);

Modules/_testcapimodule.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3928,9 +3928,6 @@ _testcapi_exec(PyObject *m)
39283928
if (_PyTestCapi_Init_Import(m) < 0) {
39293929
return -1;
39303930
}
3931-
if (_PyTestCapi_Init_Capsule(m) < 0) {
3932-
return -1;
3933-
}
39343931
if (_PyTestCapi_Init_Frame(m) < 0) {
39353932
return -1;
39363933
}

Modules/_testlimitedcapi.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ PyInit__testlimitedcapi(void)
3838
if (_PyTestLimitedCAPI_Init_Bytes(mod) < 0) {
3939
return NULL;
4040
}
41+
if (_PyTestLimitedCAPI_Init_Capsule(mod) < 0) {
42+
return NULL;
43+
}
4144
if (_PyTestLimitedCAPI_Init_Codec(mod) < 0) {
4245
return NULL;
4346
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static PyMethodDef test_methods[] = {
5757
};
5858

5959
int
60-
_PyTestCapi_Init_Capsule(PyObject *m)
60+
_PyTestLimitedCAPI_Init_Capsule(PyObject *m)
6161
{
6262
return PyModule_AddFunctions(m, test_methods);
6363
}

Modules/_testlimitedcapi/parts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
int _PyTestLimitedCAPI_Init_Abstract(PyObject *module);
2626
int _PyTestLimitedCAPI_Init_ByteArray(PyObject *module);
2727
int _PyTestLimitedCAPI_Init_Bytes(PyObject *module);
28+
int _PyTestLimitedCAPI_Init_Capsule(PyObject *module);
2829
int _PyTestLimitedCAPI_Init_Codec(PyObject *module);
2930
int _PyTestLimitedCAPI_Init_Complex(PyObject *module);
3031
int _PyTestLimitedCAPI_Init_Dict(PyObject *module);

PCbuild/_testcapi.vcxproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@
130130
<ClCompile Include="..\Modules\_testcapi\monitoring.c" />
131131
<ClCompile Include="..\Modules\_testcapi\config.c" />
132132
<ClCompile Include="..\Modules\_testcapi\import.c" />
133-
<ClCompile Include="..\Modules\_testcapi\capsule.c" />
134133
<ClCompile Include="..\Modules\_testcapi\frame.c" />
135134
<ClCompile Include="..\Modules\_testcapi\type.c" />
136135
<ClCompile Include="..\Modules\_testcapi\function.c" />

PCbuild/_testcapi.vcxproj.filters

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,6 @@
123123
<ClCompile Include="..\Modules\_testcapi\import.c">
124124
<Filter>Source Files</Filter>
125125
</ClCompile>
126-
<ClCompile Include="..\Modules\_testcapi\capsule.c">
127-
<Filter>Source Files</Filter>
128-
</ClCompile>
129126
<ClCompile Include="..\Modules\_testcapi\frame.c">
130127
<Filter>Source Files</Filter>
131128
</ClCompile>

PCbuild/_testlimitedcapi.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
<ClCompile Include="..\Modules\_testlimitedcapi\abstract.c" />
9898
<ClCompile Include="..\Modules\_testlimitedcapi\bytearray.c" />
9999
<ClCompile Include="..\Modules\_testlimitedcapi\bytes.c" />
100+
<ClCompile Include="..\Modules\_testlimitedcapi\capsule.c" />
100101
<ClCompile Include="..\Modules\_testlimitedcapi\codec.c" />
101102
<ClCompile Include="..\Modules\_testlimitedcapi\complex.c" />
102103
<ClCompile Include="..\Modules\_testlimitedcapi\dict.c" />

0 commit comments

Comments
 (0)