Skip to content

gh-127405: Emit a deprecation warning about a future change of sys.abiflags availability on Windows #131717

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 60 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
55c1c16
Emit a deprecation warning about a future change of `sys.abiflags` av…
XuehaiPan Mar 25, 2025
198ee26
📜🤖 Added by blurb_it.
blurb-it[bot] Mar 25, 2025
4a1ed1b
Update test regex
XuehaiPan Mar 25, 2025
2ebe498
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Mar 25, 2025
6bc3d73
Remove unexpected new entry
XuehaiPan Mar 25, 2025
85a8bae
ignore unused variable warning
XuehaiPan Mar 25, 2025
5172fda
Set custom `sys.__getattr__`
XuehaiPan Mar 25, 2025
e2c0326
Catch warnings in stdlib
XuehaiPan Mar 25, 2025
50a37fb
Catch warnings in stdlib
XuehaiPan Mar 25, 2025
2236ed6
Add comments for `sys.__getattr__`
XuehaiPan Mar 25, 2025
3467028
Catch warnings in stdlib
XuehaiPan Mar 25, 2025
5b4f0eb
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Mar 25, 2025
143145f
Resolve leak reference on warning failure
XuehaiPan Mar 25, 2025
0fd098f
Revert "Resolve leak reference on warning failure"
XuehaiPan Mar 25, 2025
abc1638
Add more tests
XuehaiPan Mar 25, 2025
0a69992
Only add `sys.__getattr__` on Windows
XuehaiPan Mar 25, 2025
d49abc9
Update code examples in docs
XuehaiPan Mar 25, 2025
8aa5556
Update code examples in docs
XuehaiPan Mar 25, 2025
299c0d3
properly indent code
XuehaiPan Mar 25, 2025
6c4bb07
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Mar 25, 2025
4503529
Revert "Only add `sys.__getattr__` on Windows"
XuehaiPan Mar 25, 2025
437ba52
Extract common code into defs
XuehaiPan Mar 25, 2025
f20232a
Add migration guide in docs
XuehaiPan Mar 25, 2025
5401970
Add blanklines
XuehaiPan Mar 25, 2025
55160bf
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Mar 25, 2025
2eeac04
Add more details in warning message
XuehaiPan Mar 26, 2025
ac8005c
Add more details in warning message
XuehaiPan Mar 26, 2025
cfeaa3c
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Mar 26, 2025
65297cd
Resolve unused variable warning
XuehaiPan Mar 26, 2025
ba015a3
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Mar 27, 2025
4148d8c
Fix code indentation
XuehaiPan Mar 27, 2025
78c0cab
Merge branch 'main' into windows-add-sys-abiflags
graingert Mar 29, 2025
7e84118
Handle warnings in unittest marker
XuehaiPan Mar 29, 2025
49f8d89
Clarify comments
XuehaiPan Mar 29, 2025
56c7d91
Update docs
XuehaiPan Mar 29, 2025
7884a62
Simplify `sys.abiflags` in `sysconfig` and `site`
XuehaiPan Mar 29, 2025
a5739ba
Simplify `sys.abiflags` in `sysconfig` and `site`
XuehaiPan Mar 29, 2025
21ae49d
Revert "Simplify `sys.abiflags` in `sysconfig` and `site`"
XuehaiPan Mar 29, 2025
74454ab
Revert "Simplify `sys.abiflags` in `sysconfig` and `site`"
XuehaiPan Mar 29, 2025
45be11d
Simplify `sys.abiflags` in `site`
XuehaiPan Mar 29, 2025
0864441
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Mar 30, 2025
1b8439b
Apply suggestions from code review
XuehaiPan Mar 30, 2025
bec62dc
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Mar 30, 2025
66c7b90
Resolve unused function warning
XuehaiPan Mar 30, 2025
0d30914
Add todo comments around workarounds
XuehaiPan Mar 30, 2025
659e573
Move migration guide to What's New docs
XuehaiPan Mar 30, 2025
458ef7d
Apply suggestions from code review
XuehaiPan Mar 30, 2025
2ff7082
Apply suggestions from code review
XuehaiPan Mar 30, 2025
2e79345
Add a todo note in docs
XuehaiPan Mar 30, 2025
36efb72
Add message regex in warning filters
XuehaiPan Mar 31, 2025
25b299a
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Mar 31, 2025
d23ab00
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Apr 13, 2025
c8ec513
Add `sysconfig.get_config_vars` to what's new notes
XuehaiPan Apr 13, 2025
a4c575b
Fix auto merge commit
XuehaiPan Apr 13, 2025
96b224d
Update tests
XuehaiPan Apr 13, 2025
81ef28e
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Apr 14, 2025
1b634c4
Update todo comments
XuehaiPan Apr 14, 2025
2381107
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan Apr 16, 2025
958dd06
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan May 1, 2025
5ad6305
Merge branch 'main' into windows-add-sys-abiflags
XuehaiPan May 6, 2025
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
48 changes: 48 additions & 0 deletions Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,54 @@ always available. Unless explicitly noted otherwise, all variables are read-only

.. availability:: Unix.

.. versionchanged:: next
A deprecation warning will be emitted if the :data:`sys.abiflags` member
is accessed on Windows before Python 3.16.
For example:

.. code-block:: python

>>> import sys
>>> getattr(sys, 'abiflags', None) # on Windows
<python-input-1>:1: DeprecationWarning: sys.abiflags will be set to a meaningful value on all platforms ...
>>> hasattr(sys, 'abiflags') # on Windows
<python-input-2>:1: DeprecationWarning: sys.abiflags will be set to a meaningful value on all platforms ...
False

To suppress this warning, use the :mod:`warnings` module:

.. code-block:: python

import warnings

with warnings.catch_warnings():
# ignore DeprecationWarning on sys.abiflags change on Windows
warnings.simplefilter('ignore', DeprecationWarning)
abiflags = getattr(sys, 'abiflags', '')

Due to historical reasons, :data:`sys.abiflags` is not covered by
:pep:`3149` on Windows. Now we have multiple builds, such as the
:term:`free-threaded <free threading>` build, that provide different ABIs.
:data:`sys.abiflags` is now required under many circumstances to determine
the ABI of the Python interpreter.

The :data:`sys.abiflags` member will be set to a meaningful value on
Windows in Python 3.16. This means the :data:`sys.abiflags` member will
always be available on all platforms starting from Python 3.16.

The following table shows how to migrate from the old code to the new code
without changing the behavior:

+---------------------------------------+---------------------------------------------------------------------+
| Code prior to Python 3.14 | Code prior to Python 3.16 with the same behavior |
+=======================================+=====================================================================+
| ``sys.abiflags`` | ``sys.abiflags`` |
+---------------------------------------+---------------------------------------------------------------------+
| ``getattr(sys, 'abiflags', default)`` | ``sys.abiflags if not sys.platform.startswith('win') else default`` |
+---------------------------------------+---------------------------------------------------------------------+
| ``hasattr(sys, 'abiflags')`` | ``not sys.platform.startswith('win')`` |
+---------------------------------------+---------------------------------------------------------------------+


.. function:: addaudithook(hook)

Expand Down
13 changes: 3 additions & 10 deletions Lib/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,6 @@ def joinuser(*args):
# Same to sysconfig.get_path('purelib', os.name+'_user')
def _get_path(userbase):
version = sys.version_info
if hasattr(sys, 'abiflags') and 't' in sys.abiflags:
abi_thread = 't'
else:
abi_thread = ''

implementation = _get_implementation()
implementation_lower = implementation.lower()
if os.name == 'nt':
Expand All @@ -332,6 +327,7 @@ def _get_path(userbase):
if sys.platform == 'darwin' and sys._framework:
return f'{userbase}/lib/{implementation_lower}/site-packages'

abi_thread = 't' if 't' in sys.abiflags else ''
return f'{userbase}/lib/python{version[0]}.{version[1]}{abi_thread}/site-packages'


Expand Down Expand Up @@ -400,11 +396,8 @@ def getsitepackages(prefixes=None):

implementation = _get_implementation().lower()
ver = sys.version_info
if hasattr(sys, 'abiflags') and 't' in sys.abiflags:
abi_thread = 't'
else:
abi_thread = ''
if os.sep == '/':
if os.name != 'nt':
abi_thread = 't' if 't' in sys.abiflags else ''
libdirs = [sys.platlibdir]
if sys.platlibdir != "lib":
libdirs.append("lib")
Expand Down
18 changes: 13 additions & 5 deletions Lib/sysconfig/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ def get_default_scheme():

def get_makefile_filename():
"""Return the path of the Makefile."""
import warnings

# GH-127429: When cross-compiling, use the Makefile from the target, instead of the host Python.
if cross_base := os.environ.get('_PYTHON_PROJECT_BASE'):
Expand All @@ -333,7 +334,12 @@ def get_makefile_filename():
if _PYTHON_BUILD:
return os.path.join(_PROJECT_BASE, "Makefile")

if hasattr(sys, 'abiflags'):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are there any details about the existence of sys.abiflags for cross-compiling for Windows on Ubuntu? I found it might be non-trivial to replace the following with one another:

hasattr(sys, 'abiflags')
os.name == 'nt'  # os.name != 'posix'
not sys.platform.startswith('win')

with warnings.catch_warnings():
# ignore DeprecationWarning on sys.abiflags change on Windows
warnings.simplefilter('ignore', DeprecationWarning)
has_abiflags = hasattr(sys, 'abiflags')

if has_abiflags:
config_dir_name = f'config-{_PY_VERSION_SHORT}{sys.abiflags}'
else:
config_dir_name = 'config'
Expand Down Expand Up @@ -496,6 +502,8 @@ def get_path(name, scheme=get_default_scheme(), vars=None, expand=True):


def _init_config_vars():
import warnings

global _CONFIG_VARS
_CONFIG_VARS = {}

Expand All @@ -504,10 +512,10 @@ def _init_config_vars():
base_prefix = _BASE_PREFIX
base_exec_prefix = _BASE_EXEC_PREFIX

try:
abiflags = sys.abiflags
except AttributeError:
abiflags = ''
with warnings.catch_warnings():
# ignore DeprecationWarning on sys.abiflags change on Windows
warnings.simplefilter('ignore', DeprecationWarning)
abiflags = getattr(sys, 'abiflags', '')

if os.name == 'posix':
_init_posix(_CONFIG_VARS)
Expand Down
8 changes: 7 additions & 1 deletion Lib/test/pythoninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@ def get_infos(self):

def copy_attributes(info_add, obj, name_fmt, attributes, *, formatter=None):
for attr in attributes:
value = getattr(obj, attr, None)
if attr == 'abiflags':
with warnings.catch_warnings():
# ignore DeprecationWarning on sys.abiflags change on Windows
warnings.simplefilter("ignore", DeprecationWarning)
value = getattr(obj, attr, None)
else:
value = getattr(obj, attr, None)
if value is None:
continue
name = name_fmt % attr
Expand Down
7 changes: 7 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,13 @@ def check_bolt_optimized():
return '--enable-bolt' in config_args


with warnings.catch_warnings():
# ignore DeprecationWarning on sys.abiflags change on Windows
warnings.simplefilter('ignore', DeprecationWarning)
# Equal to `not sys.platform.startswith('win')` prior to 3.16
HAS_SYS_ABIFLAGS = hasattr(sys, 'abiflags')


Py_GIL_DISABLED = bool(sysconfig.get_config_var('Py_GIL_DISABLED'))

def requires_gil_enabled(msg="needs the GIL enabled"):
Expand Down
31 changes: 30 additions & 1 deletion Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,35 @@ def test_attributes(self):
if not sys.platform.startswith('win'):
self.assertIsInstance(sys.abiflags, str)

# test hasattr(sys, 'abiflags') == (os.name != 'nt)
self.assertEqual(os.name, 'posix')
else:
absent = object()
with self.assertWarnsRegex(
DeprecationWarning,
r'sys\.abiflags will be set\b.*\bon all platforms',
):
self.assertIs(getattr(sys, 'abiflags', absent), absent)
with self.assertWarnsRegex(
DeprecationWarning,
r'sys\.abiflags will be set\b.*\bon all platforms',
):
self.assertFalse(hasattr(sys, 'abiflags'))

# Emit a deprecated warning and also raise an AttributeError
with self.assertRaisesRegex(
AttributeError,
r"module 'sys' has no attribute 'abiflags'",
):
with self.assertWarnsRegex(
DeprecationWarning,
r'sys\.abiflags will be set\b.*\bon all platforms',
):
_ = sys.abiflags

# test hasattr(sys, 'abiflags') == (os.name != 'nt)
self.assertEqual(os.name, 'nt')

def test_thread_info(self):
info = sys.thread_info
self.assertEqual(len(info), 3)
Expand Down Expand Up @@ -1332,7 +1361,7 @@ def test_pystats(self):
sys._stats_dump()

@test.support.cpython_only
@unittest.skipUnless(hasattr(sys, 'abiflags'), 'need sys.abiflags')
@unittest.skipUnless(support.HAS_SYS_ABIFLAGS, 'need sys.abiflags')
def test_disable_gil_abi(self):
self.assertEqual('t' in sys.abiflags, support.Py_GIL_DISABLED)

Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,7 @@ Todd R. Palmer
Juan David Ibáñez Palomar
Nicola Palumbo
Jan Palus
Xuehai Pan
Yongzhi Pan
Martin Panter
Mathias Panzenböck
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Emit a :exc:`DeprecationWarning` about a future change of :data:`sys.abiflags` availability on Windows. Patch by Xuehai Pan.
102 changes: 97 additions & 5 deletions Python/sysmodule.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/* System module */

/*
Expand Down Expand Up @@ -36,7 +35,7 @@ Data members:
#include "pycore_pystats.h" // _Py_PrintSpecializationStats()
#include "pycore_structseq.h" // _PyStructSequence_InitBuiltinWithFlags()
#include "pycore_sysmodule.h" // export _PySys_GetSizeOf()
#include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal()
#include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal(), _PyUnicode_EqualToASCIIString()

#include "pydtrace.h" // PyDTrace_AUDIT()
#include "osdefs.h" // DELIM
Expand Down Expand Up @@ -75,6 +74,25 @@ module sys
#include "clinic/sysmodule.c.h"


#ifndef ABIFLAGS

// XXX: remove this and related code after set sys.abiflags on Windows in 3.16.
static int
_warn_incoming_sys_abiflags_change()
{
return PyErr_WarnEx(
PyExc_DeprecationWarning,
"sys.abiflags will be set to a meaningful value on all platforms "
"in Python 3.16 instead of absent.\n\n"
"Please consider using `warnings.simplefilter()` with the "
"`warnings.catch_warnings()` context manager.\n"
"Or update the code with `if sys.platform.startswith('win')` "
"condition.",
/*stack_level=*/1);
}

#endif

PyObject *
_PySys_GetRequiredAttr(PyObject *name)
{
Expand All @@ -92,6 +110,14 @@ _PySys_GetRequiredAttr(PyObject *name)
}
PyObject *value;
if (PyDict_GetItemRef(sysdict, name, &value) == 0) {
#ifndef ABIFLAGS
if (_PyUnicode_EqualToASCIIString(name, "abiflags")) {
if (_warn_incoming_sys_abiflags_change() < 0) {
Py_XDECREF(value);
return NULL;
}
}
#endif
PyErr_Format(PyExc_RuntimeError, "lost sys.%U", name);
}
return value;
Expand All @@ -108,6 +134,14 @@ _PySys_GetRequiredAttrString(const char *name)
}
PyObject *value;
if (PyDict_GetItemStringRef(sysdict, name, &value) == 0) {
#ifndef ABIFLAGS
if (strcmp(name, "abiflags") == 0) {
if (_warn_incoming_sys_abiflags_change() < 0) {
Py_XDECREF(value);
return NULL;
}
}
#endif
PyErr_Format(PyExc_RuntimeError, "lost sys.%s", name);
}
return value;
Expand All @@ -129,7 +163,17 @@ _PySys_GetOptionalAttr(PyObject *name, PyObject **value)
*value = NULL;
return 0;
}
return PyDict_GetItemRef(sysdict, name, value);
int ret = PyDict_GetItemRef(sysdict, name, value);
#ifndef ABIFLAGS
if (ret == 0 && _PyUnicode_EqualToASCIIString(name, "abiflags")) {
if (_warn_incoming_sys_abiflags_change() < 0) {
Py_XDECREF(*value);
*value = NULL;
return -1;
}
}
#endif
return ret;
}

int
Expand All @@ -141,7 +185,17 @@ _PySys_GetOptionalAttrString(const char *name, PyObject **value)
*value = NULL;
return 0;
}
return PyDict_GetItemStringRef(sysdict, name, value);
int ret = PyDict_GetItemStringRef(sysdict, name, value);
#ifndef ABIFLAGS
if (ret == 0 && strcmp(name, "abiflags") == 0) {
if (_warn_incoming_sys_abiflags_change() < 0) {
Py_XDECREF(*value);
*value = NULL;
return -1;
}
}
#endif
return ret;
}

PyObject *
Expand All @@ -154,14 +208,23 @@ PySys_GetObject(const char *name)
}
PyObject *exc = _PyErr_GetRaisedException(tstate);
PyObject *value;
(void) PyDict_GetItemStringRef(sysdict, name, &value);
int ret = PyDict_GetItemStringRef(sysdict, name, &value);
/* XXX Suppress a new exception if it was raised and restore
* the old one. */
if (_PyErr_Occurred(tstate)) {
PyErr_FormatUnraisable("Exception ignored in PySys_GetObject()");
}
_PyErr_SetRaisedException(tstate, exc);
Py_XDECREF(value); // return a borrowed reference
#ifndef ABIFLAGS
if (ret == 0 && strcmp(name, "abiflags") == 0) {
if (_warn_incoming_sys_abiflags_change() < 0) {
return NULL;
}
}
#else
(void) ret; // ignore unused variable warning
#endif
return value;
}

Expand Down Expand Up @@ -921,6 +984,33 @@ sys_exit_impl(PyObject *module, PyObject *status)
}


// This function is used to warn about the future change of sys.abiflags
// from absent to a meaningful value on all platforms.
// It can be removed when the change is made.
static PyObject *
sys___getattr__(PyObject *module, PyObject *name)
{
PyObject *value = NULL;
if (_PySys_GetOptionalAttr(name, &value) < 0) {
Py_XDECREF(value);
return NULL;
}
if (value == NULL) {
PyErr_Clear();
PyErr_Format(PyExc_AttributeError,
"module 'sys' has no attribute '%U'", name);
}
return value;
}

PyDoc_STRVAR(sysmodule__getattr___doc,
"__getattr__($module, name, /)\n"
"--\n"
"\n"
"Get a sys attribute by name.\n"
);


static PyObject *
get_utf8_unicode(void)
{
Expand Down Expand Up @@ -2651,6 +2741,8 @@ static PyMethodDef sys_methods[] = {
SYS_EXC_INFO_METHODDEF
SYS_EXCEPTHOOK_METHODDEF
SYS_EXIT_METHODDEF
{"__getattr__", _PyCFunction_CAST(sys___getattr__),
METH_O, sysmodule__getattr___doc},
SYS_GETDEFAULTENCODING_METHODDEF
SYS_GETDLOPENFLAGS_METHODDEF
SYS_GETALLOCATEDBLOCKS_METHODDEF
Expand Down
Loading