summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Waygood <Alex.Waygood@Gmail.com>2024-05-26 12:34:48 (GMT)
committerGitHub <noreply@github.com>2024-05-26 12:34:48 (GMT)
commit008bc04dcb3b1fa6d7c11ed8050467dfad3090a9 (patch)
tree57fde6c8cc110c90e801fc5c2bda9e7bba5928d4
parentb5b7dc98c94100e992a5409d24bf035d88c7b2cd (diff)
downloadcpython-008bc04dcb3b1fa6d7c11ed8050467dfad3090a9.zip
cpython-008bc04dcb3b1fa6d7c11ed8050467dfad3090a9.tar.gz
cpython-008bc04dcb3b1fa6d7c11ed8050467dfad3090a9.tar.bz2
gh-119562: Remove AST nodes deprecated since Python 3.8 (#119563)
-rw-r--r--Doc/whatsnew/3.14.rst30
-rw-r--r--Lib/ast.py174
-rw-r--r--Lib/test/test_ast.py416
-rw-r--r--Misc/NEWS.d/next/Library/2024-05-25-20-20-42.gh-issue-119562.DyplWc.rst3
4 files changed, 38 insertions, 585 deletions
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 39172ac..bc12d4b 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 031bab4..c5d495e 100644
--- a/Lib/ast.py
+++ b/Lib/ast.py
@@ -508,27 +508,6 @@ class NodeVisitor(object):
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 @@ _DEPRECATED_CLASS_MESSAGE = (
"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 @@ class _Unparser(NodeVisitor):
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 8a4374c..18b2f7f 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -8,9 +8,7 @@ import sys
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 @@ except ImportError:
_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 @@ single_tests = [
# 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 @@ eval_tests = [
"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 @@ class AST_Tests(unittest.TestCase):
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 @@ class AST_Tests(unittest.TestCase):
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 @@ class AST_Tests(unittest.TestCase):
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 @@ class ASTValidatorTests(unittest.TestCase):
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 @@ class ASTValidatorTests(unittest.TestCase):
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 @@ class EndPositionTests(unittest.TestCase):
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 0000000..dd23466
--- /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.