Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions test cases/python/12 extmodule limited api ft/limited.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <Python.h>

#ifndef Py_LIMITED_API
#error Py_LIMITED_API must be defined.
#elif Py_LIMITED_API != 0x030f0000
#error Wrong value for Py_LIMITED_API
#endif

static PyObject *
hello(PyObject * Py_UNUSED(self), PyObject * Py_UNUSED(args)) {
return PyUnicode_FromString("hello world");
}

static struct PyMethodDef methods[] = {
{ "hello", hello, METH_NOARGS, NULL },
{ NULL, NULL, 0, NULL },
};

PyABIInfo_VAR(abi_info);

static PySlot limited_module_slots[] = {
PySlot_STATIC_DATA(Py_mod_name, "limited"),
PySlot_STATIC_DATA(Py_mod_methods, methods),
PySlot_STATIC_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED),
PySlot_STATIC_DATA(Py_mod_abi, &abi_info),
PySlot_END,
};

PyMODEXPORT_FUNC PyModExport_limited(void) {
return limited_module_slots;
}

PyMODINIT_FUNC PyInit_limited(void) {
PyErr_SetString(PyExc_NotImplementedError, "legacy init not supported");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this better than not defining the PyInit_ symbol at all?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I don't recall anymore why I did it that way in the stable-abi-testing repo, but there was probably a reason. Yes, it's one of these things :-).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked upstream, it's done the same way there in the one test package they have:

https://github.com/python/cpython/blob/4ae1a260c7dbada6db099d3335a784b5aae91723/Lib/test/test_cext/extension.c#L145

so resolving.

return NULL;
}
22 changes: 22 additions & 0 deletions test cases/python/12 extmodule limited api ft/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
project('Python limited api ft', 'c',
default_options : ['buildtype=release', 'werror=true'])

py_mod = import('python')
py = py_mod.find_installation()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: more idiomatic to collapse these 2 lines to 1 line and not use a py_mod variable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was copying the existing test, but I suppose I can change that.


if py.language_version().version_compare('<3.15')
error('MESON_SKIP_TEST: Py_TARGET_ABI3T is supported since 3.15.0a8')
endif

ext_mod_limited = py.extension_module('limited',
'limited.c',
limited_api: '3.15',
install: true,
)

test('load-test',
py,
args: [files('test_limited.py')],
env: { 'PYTHONPATH': meson.current_build_dir() },
workdir: meson.current_source_dir()
)
6 changes: 6 additions & 0 deletions test cases/python/12 extmodule limited api ft/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"installed": [
{"type": "python_limited_lib", "file": "usr/@PYTHON_PLATLIB@/limited"},
{"type": "py_limited_implib", "file": "usr/@PYTHON_PLATLIB@/limited"}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from limited import hello

def test_hello():
assert hello() == "hello world"

test_hello()
4 changes: 2 additions & 2 deletions test cases/python/9 extmodule limited api/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ project('Python limited api', 'c',
py_mod = import('python')
py = py_mod.find_installation()

if py.get_variable('Py_GIL_DISABLED', 0) == 1 and py.language_version().version_compare('<3.15')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this stay? This is not supported on 3.14 Maybe add a code comment saying that limited.c doesn't use PyModExport, hence this test case doesn't support use of the limited API under free-threading? Or extend the error message below to say that. Because I was slightly confused about why this wouldn't work for a second.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed, resolving.

error('MESON_SKIP_TEST: Freethreading Python does not support limited API')
if py.get_variable('Py_GIL_DISABLED', 0) == 1
error('MESON_SKIP_TEST: Freethreading Python does not support (old) limited API')
endif

ext_mod_limited = py.extension_module('limited',
Expand Down
33 changes: 32 additions & 1 deletion unittests/pythontests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2016-2021 The Meson development team

import glob, os, pathlib, shutil, subprocess, sys, unittest
import glob, os, pathlib, shutil, subprocess, sys, sysconfig, unittest

from run_tests import (
Backend
Expand Down Expand Up @@ -121,3 +121,34 @@ def test_limited_api_linked_correct_lib(self):
self.assertIn(limited_dep_name, output.decode())
else:
raise self.skipTest('Test needs either dumpbin(MSVC) or objdump(mingw).')

def test_abi3t_linked_correct_lib(self):
if sysconfig.get_config_var('Py_GIL_DISABLED') != 1:
return self.skipTest('Test only run with freethreading Python')
if not is_windows():
return self.skipTest('Test only run on Windows.')

testdir = os.path.join(self.src_root, 'test cases', 'python', '12 extmodule limited api ft')

self.init(testdir)
self.build()

from importlib.machinery import EXTENSION_SUFFIXES
limited_suffix = EXTENSION_SUFFIXES[1]

limited_library_path = os.path.join(self.builddir, f'limited{limited_suffix}')
self.assertPathExists(limited_library_path)

limited_dep_name = 'python3t.dll'
if shutil.which('dumpbin'):
# MSVC
output = subprocess.check_output(['dumpbin', '/DEPENDENTS', limited_library_path],
stderr=subprocess.STDOUT)
self.assertIn(limited_dep_name, output.decode())
elif shutil.which('objdump'):
# mingw
output = subprocess.check_output(['objdump', '-p', limited_library_path],
stderr=subprocess.STDOUT)
self.assertIn(limited_dep_name, output.decode())
else:
raise self.skipTest('Test needs either dumpbin(MSVC) or objdump(mingw).')
Loading