diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index a24ecac861e76b..10b8f4c474fb92 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -1166,6 +1166,7 @@ the variables: single: PyExc_PendingDeprecationWarning single: PyExc_ResourceWarning single: PyExc_RuntimeWarning + single: PyExc_SoftDeprecationWarning single: PyExc_SyntaxWarning single: PyExc_UnicodeWarning single: PyExc_UserWarning @@ -1189,6 +1190,8 @@ the variables: +------------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_RuntimeWarning` | :exc:`RuntimeWarning` | | +------------------------------------------+---------------------------------+----------+ +| :c:data:`PyExc_SoftDeprecationWarning` | :exc:`SoftDeprecationWarning` | | ++------------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_SyntaxWarning` | :exc:`SyntaxWarning` | | +------------------------------------------+---------------------------------+----------+ | :c:data:`PyExc_UnicodeWarning` | :exc:`UnicodeWarning` | | @@ -1199,6 +1202,9 @@ the variables: .. versionadded:: 3.2 :c:data:`PyExc_ResourceWarning`. +.. versionadded:: 3.13 + :c:data:`PyExc_SoftDeprecationWarning`. + Notes: .. [3] diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 7fb002cd80369b..e3dc68335559b3 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -240,6 +240,7 @@ var,PyExc_ReferenceError,3.2,, var,PyExc_ResourceWarning,3.7,, var,PyExc_RuntimeError,3.2,, var,PyExc_RuntimeWarning,3.2,, +var,PyExc_SoftDeprecationWarning,3.13,, var,PyExc_StopAsyncIteration,3.7,, var,PyExc_StopIteration,3.2,, var,PyExc_SyntaxError,3.2,, diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 8e574b8334e445..f311e1fc6c5ebd 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -802,6 +802,19 @@ The following exceptions are used as warning categories; see the The deprecation policy is described in :pep:`387`. +.. exception:: SoftDeprecationWarning + + Base class for warnings about soft deprecated features when those warnings + are intended for other Python developers. + + Ignored by the default warning filters, except in the ``__main__`` module. + Enabling the :ref:`Python Development Mode ` shows this warning. + + The soft deprecation policy is described in :pep:`387`. + + .. versionadded:: 3.13 + + .. exception:: PendingDeprecationWarning Base class for warnings about features which are obsolete and diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index c0e9e924c8e82f..541e1d866f29a3 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -76,6 +76,9 @@ New Features Other Language Changes ====================== +* Add :exc:`SoftDeprecationWarning` warning category to implement soft + deprecation. The soft deprecation policy is described in :pep:`387`. + (Contributed by Victor Stinner in :gh:`106137`.) New Modules @@ -447,6 +450,10 @@ New Features If the assertion fails, make sure that the size is set before. (Contributed by Victor Stinner in :gh:`106168`.) +* Add ``PyExc_SoftDeprecationWarning`` warning category to implement soft + deprecation. The soft deprecation policy is described in :pep:`387`. + (Contributed by Victor Stinner in :gh:`106137`.) + Porting to Python 3.13 ---------------------- diff --git a/Include/pyerrors.h b/Include/pyerrors.h index d089fa71779330..ab192e75ccaf90 100644 --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -153,6 +153,7 @@ PyAPI_DATA(PyObject *) PyExc_Warning; PyAPI_DATA(PyObject *) PyExc_UserWarning; PyAPI_DATA(PyObject *) PyExc_DeprecationWarning; PyAPI_DATA(PyObject *) PyExc_PendingDeprecationWarning; +PyAPI_DATA(PyObject *) PyExc_SoftDeprecationWarning; PyAPI_DATA(PyObject *) PyExc_SyntaxWarning; PyAPI_DATA(PyObject *) PyExc_RuntimeWarning; PyAPI_DATA(PyObject *) PyExc_FutureWarning; diff --git a/Lib/test/exception_hierarchy.txt b/Lib/test/exception_hierarchy.txt index 1eca123be0fecb..7f96510df2bbd5 100644 --- a/Lib/test/exception_hierarchy.txt +++ b/Lib/test/exception_hierarchy.txt @@ -62,6 +62,7 @@ BaseException ├── PendingDeprecationWarning ├── ResourceWarning ├── RuntimeWarning + ├── SoftDeprecationWarning ├── SyntaxWarning ├── UnicodeWarning └── UserWarning diff --git a/Lib/test/support/warnings_helper.py b/Lib/test/support/warnings_helper.py index c1bf0562300678..1825f70cbada26 100644 --- a/Lib/test/support/warnings_helper.py +++ b/Lib/test/support/warnings_helper.py @@ -13,6 +13,13 @@ def import_deprecated(name): return importlib.import_module(name) +def import_soft_deprecated(name): + """Import *name* while suppressing SoftDeprecationWarning.""" + with warnings.catch_warnings(): + warnings.simplefilter('ignore', category=SoftDeprecationWarning) + return importlib.import_module(name) + + def check_syntax_warning(testcase, statement, errtext='', *, lineno=1, offset=None): # Test also that a warning is emitted only once. diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 94298003063593..c04a09bbc73788 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -698,8 +698,10 @@ def test_xdev(self): else: expected_filters = ("default::Warning " "default::DeprecationWarning " + "default::SoftDeprecationWarning " "ignore::DeprecationWarning " "ignore::PendingDeprecationWarning " + "ignore::SoftDeprecationWarning " "ignore::ImportWarning " "ignore::ResourceWarning") @@ -768,8 +770,10 @@ def test_warnings_filter_precedence(self): if not support.Py_DEBUG: expected_filters += (" " "default::DeprecationWarning " + "default::SoftDeprecationWarning " "ignore::DeprecationWarning " "ignore::PendingDeprecationWarning " + "ignore::SoftDeprecationWarning " "ignore::ImportWarning " "ignore::ResourceWarning") diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py index 1a55da39bdc58d..4033f9c6c00b17 100644 --- a/Lib/test/test_pickle.py +++ b/Lib/test/test_pickle.py @@ -542,7 +542,8 @@ def test_exceptions(self): RecursionError, EncodingWarning, BaseExceptionGroup, - ExceptionGroup): + ExceptionGroup, + SoftDeprecationWarning): continue if exc is not OSError and issubclass(exc, OSError): self.assertEqual(reverse_mapping('builtins', name), diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 038c978e7bbd02..8ec420b01292b7 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -274,6 +274,7 @@ def test_windows_feature_macros(self): "PyExc_ResourceWarning", "PyExc_RuntimeError", "PyExc_RuntimeWarning", + "PyExc_SoftDeprecationWarning", "PyExc_StopAsyncIteration", "PyExc_StopIteration", "PyExc_SyntaxError", diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 9e680c847dab7b..94ce5c1cd61ea2 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1242,8 +1242,10 @@ def test_default_filter_configuration(self): main_module_filter = "__main__" expected_default_filters = [ ('default', None, DeprecationWarning, main_module_filter, 0), + ('default', None, SoftDeprecationWarning, main_module_filter, 0), ('ignore', None, DeprecationWarning, None, 0), ('ignore', None, PendingDeprecationWarning, None, 0), + ('ignore', None, SoftDeprecationWarning, None, 0), ('ignore', None, ImportWarning, None, 0), ('ignore', None, ResourceWarning, None, 0), ] diff --git a/Lib/warnings.py b/Lib/warnings.py index 32e58072b9cc33..c73363c7c2a4b0 100644 --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -529,6 +529,13 @@ def _deprecated(name, message=_DEPRECATED_MSG, *, remove, _version=sys.version_i warn(msg, DeprecationWarning, stacklevel=3) +def _soft_deprecated(msg): + # only emit SoftDeprecationWarning in the Python Development Mode + # and if Python is built in debug mode + if sys.flags.dev_mode or hasattr(sys, 'gettotalrefcount'): + warn(msg, SoftDeprecationWarning, stacklevel=3) + + # Private utility function called by _PyErr_WarnUnawaitedCoroutine def _warn_unawaited_coroutine(coro): msg_lines = [ @@ -587,8 +594,11 @@ def _filters_mutated(): if not hasattr(sys, 'gettotalrefcount'): filterwarnings("default", category=DeprecationWarning, module="__main__", append=1) + filterwarnings("default", category=SoftDeprecationWarning, + module="__main__", append=1) simplefilter("ignore", category=DeprecationWarning, append=1) simplefilter("ignore", category=PendingDeprecationWarning, append=1) + simplefilter("ignore", category=SoftDeprecationWarning, append=1) simplefilter("ignore", category=ImportWarning, append=1) simplefilter("ignore", category=ResourceWarning, append=1) diff --git a/Misc/NEWS.d/next/C API/2023-06-27-16-15-47.gh-issue-106137.GysR0_.rst b/Misc/NEWS.d/next/C API/2023-06-27-16-15-47.gh-issue-106137.GysR0_.rst new file mode 100644 index 00000000000000..31931059ab7a70 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-27-16-15-47.gh-issue-106137.GysR0_.rst @@ -0,0 +1,3 @@ +Add ``PyExc_SoftDeprecationWarning`` warning category to implement soft +deprecation. The soft deprecation policy is described in :pep:`387`. Patch +by Victor Stinner. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-27-16-16-19.gh-issue-106137.hArJmO.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-27-16-16-19.gh-issue-106137.hArJmO.rst new file mode 100644 index 00000000000000..fdb5e2aa9d2925 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-27-16-16-19.gh-issue-106137.hArJmO.rst @@ -0,0 +1,3 @@ +Add :exc:`SoftDeprecationWarning` warning category to implement soft +deprecation. The soft deprecation policy is described in :pep:`387`. Patch +by Victor Stinner. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index bc7259f11816f3..fc15d916301832 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2432,3 +2432,5 @@ added = '3.13' [function.PyWeakref_GetRef] added = '3.13' +[data.PyExc_SoftDeprecationWarning] + added = '3.13' diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 015dd27ec33308..258df424559f6a 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3461,6 +3461,13 @@ SimpleExtendsException(PyExc_Warning, PendingDeprecationWarning, "in the future."); +/* + * SoftDeprecationWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, SoftDeprecationWarning, + "Base class for warnings about soft deprecated features."); + + /* * SyntaxWarning extends Warning */ @@ -3630,6 +3637,7 @@ static struct static_exception static_exceptions[] = { ITEM(PendingDeprecationWarning), ITEM(ResourceWarning), ITEM(RuntimeWarning), + ITEM(SoftDeprecationWarning), ITEM(SyntaxWarning), ITEM(UnicodeWarning), ITEM(UserWarning), diff --git a/PC/python3dll.c b/PC/python3dll.c index 65bdf326ffbc7f..e303a65e0c34ad 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -829,6 +829,7 @@ EXPORT_DATA(PyExc_ReferenceError) EXPORT_DATA(PyExc_ResourceWarning) EXPORT_DATA(PyExc_RuntimeError) EXPORT_DATA(PyExc_RuntimeWarning) +EXPORT_DATA(PyExc_SoftDeprecationWarning) EXPORT_DATA(PyExc_StopAsyncIteration) EXPORT_DATA(PyExc_StopIteration) EXPORT_DATA(PyExc_SyntaxError) diff --git a/Python/_warnings.c b/Python/_warnings.c index e4941f7b068d3f..eed08527c66df9 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -96,7 +96,7 @@ init_filters(PyInterpreterState *interp) return PyList_New(0); #else /* Other builds ignore a number of warning categories by default */ - PyObject *filters = PyList_New(5); + PyObject *filters = PyList_New(7); if (filters == NULL) { return NULL; } @@ -106,8 +106,10 @@ init_filters(PyInterpreterState *interp) PyList_SET_ITEM(filters, pos++, \ create_filter(TYPE, &_Py_ID(ACTION), MODNAME)); ADD(PyExc_DeprecationWarning, default, "__main__"); + ADD(PyExc_SoftDeprecationWarning, default, "__main__"); ADD(PyExc_DeprecationWarning, ignore, NULL); ADD(PyExc_PendingDeprecationWarning, ignore, NULL); + ADD(PyExc_SoftDeprecationWarning, ignore, NULL); ADD(PyExc_ImportWarning, ignore, NULL); ADD(PyExc_ResourceWarning, ignore, NULL); #undef ADD diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 7ca14b91c841d4..0bc3b78489fa95 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -290,6 +290,9 @@ Objects/exceptions.c - PyExc_UnicodeWarning - Objects/exceptions.c - PyExc_BytesWarning - Objects/exceptions.c - PyExc_ResourceWarning - Objects/exceptions.c - PyExc_EncodingWarning - +Objects/exceptions.c - _PyExc_SoftDeprecationWarning - +Objects/exceptions.c - PyExc_SoftDeprecationWarning - + ##----------------------- ## singletons