mirror of https://github.com/python/cpython
gh-119562: Remove AST nodes deprecated since Python 3.8 (#119563)
This commit is contained in:
parent
b5b7dc98c9
commit
008bc04dcb
|
@ -108,6 +108,36 @@ Deprecated
|
||||||
Removed
|
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
|
argparse
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
174
Lib/ast.py
174
Lib/ast.py
|
@ -508,27 +508,6 @@ class NodeVisitor(object):
|
||||||
elif isinstance(value, AST):
|
elif isinstance(value, AST):
|
||||||
self.visit(value)
|
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):
|
class NodeTransformer(NodeVisitor):
|
||||||
"""
|
"""
|
||||||
|
@ -597,142 +576,6 @@ _DEPRECATED_CLASS_MESSAGE = (
|
||||||
"use ast.Constant instead"
|
"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):
|
class slice(AST):
|
||||||
"""Deprecated AST node class."""
|
"""Deprecated AST node class."""
|
||||||
|
|
||||||
|
@ -1884,27 +1727,12 @@ class _Unparser(NodeVisitor):
|
||||||
self.set_precedence(_Precedence.BOR.next(), *node.patterns)
|
self.set_precedence(_Precedence.BOR.next(), *node.patterns)
|
||||||
self.interleave(lambda: self.write(" | "), self.traverse, node.patterns)
|
self.interleave(lambda: self.write(" | "), self.traverse, node.patterns)
|
||||||
|
|
||||||
|
|
||||||
def unparse(ast_obj):
|
def unparse(ast_obj):
|
||||||
unparser = _Unparser()
|
unparser = _Unparser()
|
||||||
return unparser.visit(ast_obj)
|
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():
|
def main():
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,7 @@ import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import types
|
import types
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
|
||||||
import weakref
|
import weakref
|
||||||
from functools import partial
|
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
try:
|
try:
|
||||||
import _testinternalcapi
|
import _testinternalcapi
|
||||||
|
@ -18,7 +16,6 @@ except ImportError:
|
||||||
_testinternalcapi = None
|
_testinternalcapi = None
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
from test.support.import_helper import import_fresh_module
|
|
||||||
from test.support import os_helper, script_helper
|
from test.support import os_helper, script_helper
|
||||||
from test.support.ast_helper import ASTTestMixin
|
from test.support.ast_helper import ASTTestMixin
|
||||||
|
|
||||||
|
@ -223,7 +220,7 @@ single_tests = [
|
||||||
# These are compiled through "eval"
|
# These are compiled through "eval"
|
||||||
# It should test all expressions
|
# It should test all expressions
|
||||||
eval_tests = [
|
eval_tests = [
|
||||||
# None
|
# Constant(value=None)
|
||||||
"None",
|
"None",
|
||||||
# BoolOp
|
# BoolOp
|
||||||
"a and b",
|
"a and b",
|
||||||
|
@ -269,9 +266,9 @@ eval_tests = [
|
||||||
"f(*[0, 1])",
|
"f(*[0, 1])",
|
||||||
# Call with a generator argument
|
# Call with a generator argument
|
||||||
"f(a for a in b)",
|
"f(a for a in b)",
|
||||||
# Num
|
# Constant(value=int())
|
||||||
"10",
|
"10",
|
||||||
# Str
|
# Constant(value=str())
|
||||||
"'string'",
|
"'string'",
|
||||||
# Attribute
|
# Attribute
|
||||||
"a.b",
|
"a.b",
|
||||||
|
@ -498,35 +495,8 @@ class AST_Tests(unittest.TestCase):
|
||||||
self.assertTrue(issubclass(ast.comprehension, ast.AST))
|
self.assertTrue(issubclass(ast.comprehension, ast.AST))
|
||||||
self.assertTrue(issubclass(ast.Gt, 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):
|
def test_field_attr_existence(self):
|
||||||
for name, item in ast.__dict__.items():
|
for name, item in ast.__dict__.items():
|
||||||
# These emit DeprecationWarnings
|
|
||||||
if name in {'Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis'}:
|
|
||||||
continue
|
|
||||||
# constructor has a different signature
|
# constructor has a different signature
|
||||||
if name == 'Index':
|
if name == 'Index':
|
||||||
continue
|
continue
|
||||||
|
@ -569,106 +539,12 @@ class AST_Tests(unittest.TestCase):
|
||||||
self.assertEqual(x.args, 2)
|
self.assertEqual(x.args, 2)
|
||||||
self.assertEqual(x.vararg, 3)
|
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):
|
def test_field_attr_writable(self):
|
||||||
x = ast.Constant(1)
|
x = ast.Constant(1)
|
||||||
# We can assign to _fields
|
# We can assign to _fields
|
||||||
x._fields = 666
|
x._fields = 666
|
||||||
self.assertEqual(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):
|
def test_classattrs(self):
|
||||||
with self.assertWarns(DeprecationWarning):
|
with self.assertWarns(DeprecationWarning):
|
||||||
x = ast.Constant()
|
x = ast.Constant()
|
||||||
|
@ -714,190 +590,6 @@ class AST_Tests(unittest.TestCase):
|
||||||
self.assertIs(ast.Constant(None).value, None)
|
self.assertIs(ast.Constant(None).value, None)
|
||||||
self.assertIs(ast.Constant(...).value, ...)
|
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):
|
def test_constant_subclasses(self):
|
||||||
class N(ast.Constant):
|
class N(ast.Constant):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -2223,32 +1915,6 @@ class ASTValidatorTests(unittest.TestCase):
|
||||||
call = ast.Call(func, args, bad_keywords)
|
call = ast.Call(func, args, bad_keywords)
|
||||||
self.expr(call, "must have Load context")
|
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):
|
def test_attribute(self):
|
||||||
attr = ast.Attribute(ast.Name("x", ast.Store()), "y", ast.Load())
|
attr = ast.Attribute(ast.Name("x", ast.Store()), "y", ast.Load())
|
||||||
self.expr(attr, "must have Load context")
|
self.expr(attr, "must have Load context")
|
||||||
|
@ -2288,19 +1954,6 @@ class ASTValidatorTests(unittest.TestCase):
|
||||||
def test_tuple(self):
|
def test_tuple(self):
|
||||||
self._sequence(ast.Tuple)
|
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')
|
@support.requires_resource('cpu')
|
||||||
def test_stdlib_validates(self):
|
def test_stdlib_validates(self):
|
||||||
for module in STDLIB_FILES:
|
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, x))
|
||||||
self.assertIsNone(ast.get_source_segment(s, y))
|
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,
|
def assertASTTransformation(self, tranformer_class,
|
||||||
initial_code, expected_code):
|
initial_code, expected_code):
|
||||||
initial_ast = ast.parse(dedent(initial_code))
|
initial_ast = ast.parse(dedent(initial_code))
|
||||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue