https://github.com/python/cpython/commit/008bc04dcb3b1fa6d7c11ed8050467dfad3090a9
commit: 008bc04dcb3b1fa6d7c11ed8050467dfad3090a9
branch: main
author: Alex Waygood <[email protected]>
committer: AlexWaygood <[email protected]>
date: 2024-05-26T12:34:48Z
summary:

gh-119562: Remove AST nodes deprecated since Python 3.8 (#119563)

files:
A Misc/NEWS.d/next/Library/2024-05-25-20-20-42.gh-issue-119562.DyplWc.rst
M Doc/whatsnew/3.14.rst
M Lib/ast.py
M Lib/test/test_ast.py

diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 39172ac60cf1e0..bc12d4b3b590dd 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -108,6 +108,36 @@ Deprecated
 Removed
 =======
 
+ast
+---
+
+* Remove the following classes. They were all deprecated since Python 3.8,
+  and have emitted deprecation warnings since Python 3.12:
+
+  * :class:`!ast.Num`
+  * :class:`!ast.Str`
+  * :class:`!ast.Bytes`
+  * :class:`!ast.NameConstant`
+  * :class:`!ast.Ellipsis`
+
+  Use :class:`ast.Constant` instead. As a consequence of these removals,
+  user-defined ``visit_Num``, ``visit_Str``, ``visit_Bytes``,
+  ``visit_NameConstant`` and ``visit_Ellipsis`` methods on custom
+  :class:`ast.NodeVisitor` subclasses will no longer be called when the
+  ``NodeVisitor`` subclass is visiting an AST. Define a ``visit_Constant``
+  method instead.
+
+  Also, remove the following deprecated properties on :class:`ast.Constant`,
+  which were present for compatibility with the now-removed AST classes:
+
+  * :attr:`!ast.Constant.n`
+  * :attr:`!ast.Constant.s`
+
+  Use :attr:`!ast.Constant.value` instead.
+
+  (Contributed by Alex Waygood in :gh:`119562`.)
+
+
 argparse
 --------
 
diff --git a/Lib/ast.py b/Lib/ast.py
index 031bab43df7579..c5d495ea1c8000 100644
--- a/Lib/ast.py
+++ b/Lib/ast.py
@@ -508,27 +508,6 @@ def generic_visit(self, node):
             elif isinstance(value, AST):
                 self.visit(value)
 
-    def visit_Constant(self, node):
-        value = node.value
-        type_name = _const_node_type_names.get(type(value))
-        if type_name is None:
-            for cls, name in _const_node_type_names.items():
-                if isinstance(value, cls):
-                    type_name = name
-                    break
-        if type_name is not None:
-            method = 'visit_' + type_name
-            try:
-                visitor = getattr(self, method)
-            except AttributeError:
-                pass
-            else:
-                import warnings
-                warnings.warn(f"{method} is deprecated; add visit_Constant",
-                              DeprecationWarning, 2)
-                return visitor(node)
-        return self.generic_visit(node)
-
 
 class NodeTransformer(NodeVisitor):
     """
@@ -597,142 +576,6 @@ def generic_visit(self, node):
     "use ast.Constant instead"
 )
 
-
-# If the ast module is loaded more than once, only add deprecated methods once
-if not hasattr(Constant, 'n'):
-    # The following code is for backward compatibility.
-    # It will be removed in future.
-
-    def _n_getter(self):
-        """Deprecated. Use value instead."""
-        import warnings
-        warnings._deprecated(
-            "Attribute n", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 
14)
-        )
-        return self.value
-
-    def _n_setter(self, value):
-        import warnings
-        warnings._deprecated(
-            "Attribute n", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 
14)
-        )
-        self.value = value
-
-    def _s_getter(self):
-        """Deprecated. Use value instead."""
-        import warnings
-        warnings._deprecated(
-            "Attribute s", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 
14)
-        )
-        return self.value
-
-    def _s_setter(self, value):
-        import warnings
-        warnings._deprecated(
-            "Attribute s", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 
14)
-        )
-        self.value = value
-
-    Constant.n = property(_n_getter, _n_setter)
-    Constant.s = property(_s_getter, _s_setter)
-
-class _ABC(type):
-
-    def __init__(cls, *args):
-        cls.__doc__ = """Deprecated AST node class. Use ast.Constant instead"""
-
-    def __instancecheck__(cls, inst):
-        if cls in _const_types:
-            import warnings
-            warnings._deprecated(
-                f"ast.{cls.__qualname__}",
-                message=_DEPRECATED_CLASS_MESSAGE,
-                remove=(3, 14)
-            )
-        if not isinstance(inst, Constant):
-            return False
-        if cls in _const_types:
-            try:
-                value = inst.value
-            except AttributeError:
-                return False
-            else:
-                return (
-                    isinstance(value, _const_types[cls]) and
-                    not isinstance(value, _const_types_not.get(cls, ()))
-                )
-        return type.__instancecheck__(cls, inst)
-
-def _new(cls, *args, **kwargs):
-    for key in kwargs:
-        if key not in cls._fields:
-            # arbitrary keyword arguments are accepted
-            continue
-        pos = cls._fields.index(key)
-        if pos < len(args):
-            raise TypeError(f"{cls.__name__} got multiple values for argument 
{key!r}")
-    if cls in _const_types:
-        import warnings
-        warnings._deprecated(
-            f"ast.{cls.__qualname__}", message=_DEPRECATED_CLASS_MESSAGE, 
remove=(3, 14)
-        )
-        return Constant(*args, **kwargs)
-    return Constant.__new__(cls, *args, **kwargs)
-
-class Num(Constant, metaclass=_ABC):
-    _fields = ('n',)
-    __new__ = _new
-
-class Str(Constant, metaclass=_ABC):
-    _fields = ('s',)
-    __new__ = _new
-
-class Bytes(Constant, metaclass=_ABC):
-    _fields = ('s',)
-    __new__ = _new
-
-class NameConstant(Constant, metaclass=_ABC):
-    __new__ = _new
-
-class Ellipsis(Constant, metaclass=_ABC):
-    _fields = ()
-
-    def __new__(cls, *args, **kwargs):
-        if cls is _ast_Ellipsis:
-            import warnings
-            warnings._deprecated(
-                "ast.Ellipsis", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 
14)
-            )
-            return Constant(..., *args, **kwargs)
-        return Constant.__new__(cls, *args, **kwargs)
-
-# Keep another reference to Ellipsis in the global namespace
-# so it can be referenced in Ellipsis.__new__
-# (The original "Ellipsis" name is removed from the global namespace later on)
-_ast_Ellipsis = Ellipsis
-
-_const_types = {
-    Num: (int, float, complex),
-    Str: (str,),
-    Bytes: (bytes,),
-    NameConstant: (type(None), bool),
-    Ellipsis: (type(...),),
-}
-_const_types_not = {
-    Num: (bool,),
-}
-
-_const_node_type_names = {
-    bool: 'NameConstant',  # should be before int
-    type(None): 'NameConstant',
-    int: 'Num',
-    float: 'Num',
-    complex: 'Num',
-    str: 'Str',
-    bytes: 'Bytes',
-    type(...): 'Ellipsis',
-}
-
 class slice(AST):
     """Deprecated AST node class."""
 
@@ -1884,27 +1727,12 @@ def visit_MatchOr(self, node):
             self.set_precedence(_Precedence.BOR.next(), *node.patterns)
             self.interleave(lambda: self.write(" | "), self.traverse, 
node.patterns)
 
+
 def unparse(ast_obj):
     unparser = _Unparser()
     return unparser.visit(ast_obj)
 
 
-_deprecated_globals = {
-    name: globals().pop(name)
-    for name in ('Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis')
-}
-
-def __getattr__(name):
-    if name in _deprecated_globals:
-        globals()[name] = value = _deprecated_globals[name]
-        import warnings
-        warnings._deprecated(
-            f"ast.{name}", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 14)
-        )
-        return value
-    raise AttributeError(f"module 'ast' has no attribute '{name}'")
-
-
 def main():
     import argparse
 
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index 8a4374c56cbc08..18b2f7ffca6083 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -8,9 +8,7 @@
 import textwrap
 import types
 import unittest
-import warnings
 import weakref
-from functools import partial
 from textwrap import dedent
 try:
     import _testinternalcapi
@@ -18,7 +16,6 @@
     _testinternalcapi = None
 
 from test import support
-from test.support.import_helper import import_fresh_module
 from test.support import os_helper, script_helper
 from test.support.ast_helper import ASTTestMixin
 
@@ -223,7 +220,7 @@ def to_tuple(t):
 # These are compiled through "eval"
 # It should test all expressions
 eval_tests = [
-  # None
+  # Constant(value=None)
   "None",
   # BoolOp
   "a and b",
@@ -269,9 +266,9 @@ def to_tuple(t):
   "f(*[0, 1])",
   # Call with a generator argument
   "f(a for a in b)",
-  # Num
+  # Constant(value=int())
   "10",
-  # Str
+  # Constant(value=str())
   "'string'",
   # Attribute
   "a.b",
@@ -498,35 +495,8 @@ def test_base_classes(self):
         self.assertTrue(issubclass(ast.comprehension, ast.AST))
         self.assertTrue(issubclass(ast.Gt, ast.AST))
 
-    def test_import_deprecated(self):
-        ast = import_fresh_module('ast')
-        depr_regex = (
-            r'ast\.{} is deprecated and will be removed in Python 3.14; '
-            r'use ast\.Constant instead'
-        )
-        for name in 'Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis':
-            with self.assertWarnsRegex(DeprecationWarning, 
depr_regex.format(name)):
-                getattr(ast, name)
-
-    def test_field_attr_existence_deprecated(self):
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', '', DeprecationWarning)
-            from ast import Num, Str, Bytes, NameConstant, Ellipsis
-
-        for name in ('Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis'):
-            item = getattr(ast, name)
-            if self._is_ast_node(name, item):
-                with self.subTest(item):
-                    with self.assertWarns(DeprecationWarning):
-                        x = item()
-                if isinstance(x, ast.AST):
-                    self.assertIs(type(x._fields), tuple)
-
     def test_field_attr_existence(self):
         for name, item in ast.__dict__.items():
-            # These emit DeprecationWarnings
-            if name in {'Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis'}:
-                continue
             # constructor has a different signature
             if name == 'Index':
                 continue
@@ -569,106 +539,12 @@ def test_arguments(self):
         self.assertEqual(x.args, 2)
         self.assertEqual(x.vararg, 3)
 
-    def test_field_attr_writable_deprecated(self):
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', '', DeprecationWarning)
-            x = ast.Num()
-        # We can assign to _fields
-        x._fields = 666
-        self.assertEqual(x._fields, 666)
-
     def test_field_attr_writable(self):
         x = ast.Constant(1)
         # We can assign to _fields
         x._fields = 666
         self.assertEqual(x._fields, 666)
 
-    def test_classattrs_deprecated(self):
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', '', DeprecationWarning)
-            from ast import Num, Str, Bytes, NameConstant, Ellipsis
-
-        with warnings.catch_warnings(record=True) as wlog:
-            warnings.filterwarnings('always', '', DeprecationWarning)
-            x = ast.Num()
-            self.assertEqual(x._fields, ('value', 'kind'))
-
-            with self.assertRaises(AttributeError):
-                x.value
-
-            with self.assertRaises(AttributeError):
-                x.n
-
-            x = ast.Num(42)
-            self.assertEqual(x.value, 42)
-            self.assertEqual(x.n, 42)
-
-            with self.assertRaises(AttributeError):
-                x.lineno
-
-            with self.assertRaises(AttributeError):
-                x.foobar
-
-            x = ast.Num(lineno=2)
-            self.assertEqual(x.lineno, 2)
-
-            x = ast.Num(42, lineno=0)
-            self.assertEqual(x.lineno, 0)
-            self.assertEqual(x._fields, ('value', 'kind'))
-            self.assertEqual(x.value, 42)
-            self.assertEqual(x.n, 42)
-
-            self.assertRaises(TypeError, ast.Num, 1, None, 2)
-            self.assertRaises(TypeError, ast.Num, 1, None, 2, lineno=0)
-
-            # Arbitrary keyword arguments are supported
-            self.assertEqual(ast.Num(1, foo='bar').foo, 'bar')
-
-            with self.assertRaisesRegex(TypeError, "Num got multiple values 
for argument 'n'"):
-                ast.Num(1, n=2)
-
-            self.assertEqual(ast.Num(42).n, 42)
-            self.assertEqual(ast.Num(4.25).n, 4.25)
-            self.assertEqual(ast.Num(4.25j).n, 4.25j)
-            self.assertEqual(ast.Str('42').s, '42')
-            self.assertEqual(ast.Bytes(b'42').s, b'42')
-            self.assertIs(ast.NameConstant(True).value, True)
-            self.assertIs(ast.NameConstant(False).value, False)
-            self.assertIs(ast.NameConstant(None).value, None)
-
-        self.assertEqual([str(w.message) for w in wlog], [
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            "Constant.__init__ missing 1 required positional argument: 
'value'. This will become "
-            'an error in Python 3.15.',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            "Constant.__init__ missing 1 required positional argument: 
'value'. This will become "
-            'an error in Python 3.15.',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            "Constant.__init__ got an unexpected keyword argument 'foo'. 
Support for "
-            'arbitrary keyword arguments is deprecated and will be removed in 
Python '
-            '3.15.',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'ast.Str is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'Attribute s is deprecated and will be removed in Python 3.14; use 
value instead',
-            'ast.Bytes is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'Attribute s is deprecated and will be removed in Python 3.14; use 
value instead',
-            'ast.NameConstant is deprecated and will be removed in Python 
3.14; use ast.Constant instead',
-            'ast.NameConstant is deprecated and will be removed in Python 
3.14; use ast.Constant instead',
-            'ast.NameConstant is deprecated and will be removed in Python 
3.14; use ast.Constant instead',
-        ])
-
     def test_classattrs(self):
         with self.assertWarns(DeprecationWarning):
             x = ast.Constant()
@@ -714,190 +590,6 @@ def test_classattrs(self):
         self.assertIs(ast.Constant(None).value, None)
         self.assertIs(ast.Constant(...).value, ...)
 
-    def test_realtype(self):
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', '', DeprecationWarning)
-            from ast import Num, Str, Bytes, NameConstant, Ellipsis
-
-        with warnings.catch_warnings(record=True) as wlog:
-            warnings.filterwarnings('always', '', DeprecationWarning)
-            self.assertIs(type(ast.Num(42)), ast.Constant)
-            self.assertIs(type(ast.Num(4.25)), ast.Constant)
-            self.assertIs(type(ast.Num(4.25j)), ast.Constant)
-            self.assertIs(type(ast.Str('42')), ast.Constant)
-            self.assertIs(type(ast.Bytes(b'42')), ast.Constant)
-            self.assertIs(type(ast.NameConstant(True)), ast.Constant)
-            self.assertIs(type(ast.NameConstant(False)), ast.Constant)
-            self.assertIs(type(ast.NameConstant(None)), ast.Constant)
-            self.assertIs(type(ast.Ellipsis()), ast.Constant)
-
-        self.assertEqual([str(w.message) for w in wlog], [
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Str is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Bytes is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.NameConstant is deprecated and will be removed in Python 
3.14; use ast.Constant instead',
-            'ast.NameConstant is deprecated and will be removed in Python 
3.14; use ast.Constant instead',
-            'ast.NameConstant is deprecated and will be removed in Python 
3.14; use ast.Constant instead',
-            'ast.Ellipsis is deprecated and will be removed in Python 3.14; 
use ast.Constant instead',
-        ])
-
-    def test_isinstance(self):
-        from ast import Constant
-
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', '', DeprecationWarning)
-            from ast import Num, Str, Bytes, NameConstant, Ellipsis
-
-        cls_depr_msg = (
-            'ast.{} is deprecated and will be removed in Python 3.14; '
-            'use ast.Constant instead'
-        )
-
-        assertNumDeprecated = partial(
-            self.assertWarnsRegex, DeprecationWarning, 
cls_depr_msg.format("Num")
-        )
-        assertStrDeprecated = partial(
-            self.assertWarnsRegex, DeprecationWarning, 
cls_depr_msg.format("Str")
-        )
-        assertBytesDeprecated = partial(
-            self.assertWarnsRegex, DeprecationWarning, 
cls_depr_msg.format("Bytes")
-        )
-        assertNameConstantDeprecated = partial(
-            self.assertWarnsRegex,
-            DeprecationWarning,
-            cls_depr_msg.format("NameConstant")
-        )
-        assertEllipsisDeprecated = partial(
-            self.assertWarnsRegex, DeprecationWarning, 
cls_depr_msg.format("Ellipsis")
-        )
-
-        for arg in 42, 4.2, 4.2j:
-            with self.subTest(arg=arg):
-                with assertNumDeprecated():
-                    n = Num(arg)
-                with assertNumDeprecated():
-                    self.assertIsInstance(n, Num)
-
-        with assertStrDeprecated():
-            s = Str('42')
-        with assertStrDeprecated():
-            self.assertIsInstance(s, Str)
-
-        with assertBytesDeprecated():
-            b = Bytes(b'42')
-        with assertBytesDeprecated():
-            self.assertIsInstance(b, Bytes)
-
-        for arg in True, False, None:
-            with self.subTest(arg=arg):
-                with assertNameConstantDeprecated():
-                    n = NameConstant(arg)
-                with assertNameConstantDeprecated():
-                    self.assertIsInstance(n, NameConstant)
-
-        with assertEllipsisDeprecated():
-            e = Ellipsis()
-        with assertEllipsisDeprecated():
-            self.assertIsInstance(e, Ellipsis)
-
-        for arg in 42, 4.2, 4.2j:
-            with self.subTest(arg=arg):
-                with assertNumDeprecated():
-                    self.assertIsInstance(Constant(arg), Num)
-
-        with assertStrDeprecated():
-            self.assertIsInstance(Constant('42'), Str)
-
-        with assertBytesDeprecated():
-            self.assertIsInstance(Constant(b'42'), Bytes)
-
-        for arg in True, False, None:
-            with self.subTest(arg=arg):
-                with assertNameConstantDeprecated():
-                    self.assertIsInstance(Constant(arg), NameConstant)
-
-        with assertEllipsisDeprecated():
-            self.assertIsInstance(Constant(...), Ellipsis)
-
-        with assertStrDeprecated():
-            s = Str('42')
-        assertNumDeprecated(self.assertNotIsInstance, s, Num)
-        assertBytesDeprecated(self.assertNotIsInstance, s, Bytes)
-
-        with assertNumDeprecated():
-            n = Num(42)
-        assertStrDeprecated(self.assertNotIsInstance, n, Str)
-        assertNameConstantDeprecated(self.assertNotIsInstance, n, NameConstant)
-        assertEllipsisDeprecated(self.assertNotIsInstance, n, Ellipsis)
-
-        with assertNameConstantDeprecated():
-            n = NameConstant(True)
-        with assertNumDeprecated():
-            self.assertNotIsInstance(n, Num)
-
-        with assertNameConstantDeprecated():
-            n = NameConstant(False)
-        with assertNumDeprecated():
-            self.assertNotIsInstance(n, Num)
-
-        for arg in '42', True, False:
-            with self.subTest(arg=arg):
-                with assertNumDeprecated():
-                    self.assertNotIsInstance(Constant(arg), Num)
-
-        assertStrDeprecated(self.assertNotIsInstance, Constant(42), Str)
-        assertBytesDeprecated(self.assertNotIsInstance, Constant('42'), Bytes)
-        assertNameConstantDeprecated(self.assertNotIsInstance, Constant(42), 
NameConstant)
-        assertEllipsisDeprecated(self.assertNotIsInstance, Constant(42), 
Ellipsis)
-        assertNumDeprecated(self.assertNotIsInstance, Constant(None), Num)
-        assertStrDeprecated(self.assertNotIsInstance, Constant(None), Str)
-        assertBytesDeprecated(self.assertNotIsInstance, Constant(None), Bytes)
-        assertNameConstantDeprecated(self.assertNotIsInstance, Constant(1), 
NameConstant)
-        assertEllipsisDeprecated(self.assertNotIsInstance, Constant(None), 
Ellipsis)
-
-        class S(str): pass
-        with assertStrDeprecated():
-            self.assertIsInstance(Constant(S('42')), Str)
-        with assertNumDeprecated():
-            self.assertNotIsInstance(Constant(S('42')), Num)
-
-    def test_constant_subclasses_deprecated(self):
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', '', DeprecationWarning)
-            from ast import Num
-
-        with warnings.catch_warnings(record=True) as wlog:
-            warnings.filterwarnings('always', '', DeprecationWarning)
-            class N(ast.Num):
-                def __init__(self, *args, **kwargs):
-                    super().__init__(*args, **kwargs)
-                    self.z = 'spam'
-            class N2(ast.Num):
-                pass
-
-            n = N(42)
-            self.assertEqual(n.n, 42)
-            self.assertEqual(n.z, 'spam')
-            self.assertIs(type(n), N)
-            self.assertIsInstance(n, N)
-            self.assertIsInstance(n, ast.Num)
-            self.assertNotIsInstance(n, N2)
-            self.assertNotIsInstance(ast.Num(42), N)
-            n = N(n=42)
-            self.assertEqual(n.n, 42)
-            self.assertIs(type(n), N)
-
-        self.assertEqual([str(w.message) for w in wlog], [
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-        ])
-
     def test_constant_subclasses(self):
         class N(ast.Constant):
             def __init__(self, *args, **kwargs):
@@ -2223,32 +1915,6 @@ def test_call(self):
         call = ast.Call(func, args, bad_keywords)
         self.expr(call, "must have Load context")
 
-    def test_num(self):
-        with warnings.catch_warnings(record=True) as wlog:
-            warnings.filterwarnings('ignore', '', DeprecationWarning)
-            from ast import Num
-
-        with warnings.catch_warnings(record=True) as wlog:
-            warnings.filterwarnings('always', '', DeprecationWarning)
-            class subint(int):
-                pass
-            class subfloat(float):
-                pass
-            class subcomplex(complex):
-                pass
-            for obj in "0", "hello":
-                self.expr(ast.Num(obj))
-            for obj in subint(), subfloat(), subcomplex():
-                self.expr(ast.Num(obj), "invalid type", exc=TypeError)
-
-        self.assertEqual([str(w.message) for w in wlog], [
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-            'ast.Num is deprecated and will be removed in Python 3.14; use 
ast.Constant instead',
-        ])
-
     def test_attribute(self):
         attr = ast.Attribute(ast.Name("x", ast.Store()), "y", ast.Load())
         self.expr(attr, "must have Load context")
@@ -2288,19 +1954,6 @@ def test_list(self):
     def test_tuple(self):
         self._sequence(ast.Tuple)
 
-    def test_nameconstant(self):
-        with warnings.catch_warnings(record=True) as wlog:
-            warnings.filterwarnings('ignore', '', DeprecationWarning)
-            from ast import NameConstant
-
-        with warnings.catch_warnings(record=True) as wlog:
-            warnings.filterwarnings('always', '', DeprecationWarning)
-            self.expr(ast.NameConstant(4))
-
-        self.assertEqual([str(w.message) for w in wlog], [
-            'ast.NameConstant is deprecated and will be removed in Python 
3.14; use ast.Constant instead',
-        ])
-
     @support.requires_resource('cpu')
     def test_stdlib_validates(self):
         for module in STDLIB_FILES:
@@ -2953,69 +2606,8 @@ def test_source_segment_missing_info(self):
         self.assertIsNone(ast.get_source_segment(s, x))
         self.assertIsNone(ast.get_source_segment(s, y))
 
-class BaseNodeVisitorCases:
-    # Both `NodeVisitor` and `NodeTranformer` must raise these warnings:
-    def test_old_constant_nodes(self):
-        class Visitor(self.visitor_class):
-            def visit_Num(self, node):
-                log.append((node.lineno, 'Num', node.n))
-            def visit_Str(self, node):
-                log.append((node.lineno, 'Str', node.s))
-            def visit_Bytes(self, node):
-                log.append((node.lineno, 'Bytes', node.s))
-            def visit_NameConstant(self, node):
-                log.append((node.lineno, 'NameConstant', node.value))
-            def visit_Ellipsis(self, node):
-                log.append((node.lineno, 'Ellipsis', ...))
-        mod = ast.parse(dedent('''\
-            i = 42
-            f = 4.25
-            c = 4.25j
-            s = 'string'
-            b = b'bytes'
-            t = True
-            n = None
-            e = ...
-            '''))
-        visitor = Visitor()
-        log = []
-        with warnings.catch_warnings(record=True) as wlog:
-            warnings.filterwarnings('always', '', DeprecationWarning)
-            visitor.visit(mod)
-        self.assertEqual(log, [
-            (1, 'Num', 42),
-            (2, 'Num', 4.25),
-            (3, 'Num', 4.25j),
-            (4, 'Str', 'string'),
-            (5, 'Bytes', b'bytes'),
-            (6, 'NameConstant', True),
-            (7, 'NameConstant', None),
-            (8, 'Ellipsis', ...),
-        ])
-        self.assertEqual([str(w.message) for w in wlog], [
-            'visit_Num is deprecated; add visit_Constant',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'visit_Num is deprecated; add visit_Constant',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'visit_Num is deprecated; add visit_Constant',
-            'Attribute n is deprecated and will be removed in Python 3.14; use 
value instead',
-            'visit_Str is deprecated; add visit_Constant',
-            'Attribute s is deprecated and will be removed in Python 3.14; use 
value instead',
-            'visit_Bytes is deprecated; add visit_Constant',
-            'Attribute s is deprecated and will be removed in Python 3.14; use 
value instead',
-            'visit_NameConstant is deprecated; add visit_Constant',
-            'visit_NameConstant is deprecated; add visit_Constant',
-            'visit_Ellipsis is deprecated; add visit_Constant',
-        ])
-
-
-class NodeVisitorTests(BaseNodeVisitorCases, unittest.TestCase):
-    visitor_class = ast.NodeVisitor
-
-
-class NodeTransformerTests(ASTTestMixin, BaseNodeVisitorCases, 
unittest.TestCase):
-    visitor_class = ast.NodeTransformer
 
+class NodeTransformerTests(ASTTestMixin, unittest.TestCase):
     def assertASTTransformation(self, tranformer_class,
                                 initial_code, expected_code):
         initial_ast = ast.parse(dedent(initial_code))
diff --git 
a/Misc/NEWS.d/next/Library/2024-05-25-20-20-42.gh-issue-119562.DyplWc.rst 
b/Misc/NEWS.d/next/Library/2024-05-25-20-20-42.gh-issue-119562.DyplWc.rst
new file mode 100644
index 00000000000000..dd23466b9d2cef
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-05-25-20-20-42.gh-issue-119562.DyplWc.rst
@@ -0,0 +1,3 @@
+Remove :class:`!ast.Num`, :class:`!ast.Str`, :class:`!ast.Bytes`,
+:class:`!ast.NameConstant` and :class:`!ast.Ellipsis`. They had all emitted
+deprecation warnings since Python 3.12. Patch by Alex Waygood.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to