8000 gh-119562: Remove AST nodes deprecated since Python 3.8 (#119563) · python/cpython@008bc04 · GitHub
[go: up one dir, main page]

Skip to content

Commit 008bc04

Browse files
authored
gh-119562: Remove AST nodes deprecated since Python 3.8 (#119563)
1 parent b5b7dc9 commit 008bc04

File tree

4 files changed

+38
-585
lines changed

4 files changed

+38
-585
lines changed

Doc/whatsnew/3.14.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,36 @@ Deprecated
108108
Removed
109109
=======
110110

111+
ast
112+
---
113+
114+
* Remove the following classes. They were all deprecated since Python 3.8,
115+
and have emitted deprecation warnings since Python 3.12:
116+
117+
* :class:`!ast.Num`
118+
* :class:`!ast.Str`
119+
* :class:`!ast.Bytes`
120+
* :class:`!ast.NameConstant`
121+
* :class:`!ast.Ellipsis`
122+
123+
Use :class:`ast.Constant` instead. As a consequence of these removals,
124+
user-defined ``visit_Num``, ``visit_Str``, ``visit_Bytes``,
125+
``visit_NameConstant`` and ``visit_Ellipsis`` methods on custom
126+
:class:`ast.NodeVisitor` subclasses will no longer be called when the
127+
``NodeVisitor`` subclass is visiting an AST. Define a ``visit_Constant``
128+
method instead.
129+
130+
Also, remove the following deprecated properties on :class:`ast.Constant`,
131+
which were present for compatibility with the now-removed AST classes:
132+
133+
* :attr:`!ast.Constant.n`
134+
* :attr:`!ast.Constant.s`
135+
136+
Use :attr:`!ast.Constant.value` instead.
137+
138+
(Contributed by Alex Waygood in :gh:`119562`.)
139+
140+
111141
argparse
112142
--------
113143

Lib/ast.py

Lines changed: 1 addition & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -508,27 +508,6 @@ def generic_visit(self, node):
508508
elif isinstance(value, AST):
509509
self.visit(value)
510510

511-
def visit_Constant(self, node):
512-
value = node.value
513-
type_name = _const_node_type_names.get(type(value))
514-
if type_name is None:
515-
for cls, name in _const_node_type_names.items():
516-
if isinstance(value, cls):
517-
type_name = name
518-
break
519-
if type_name is not None:
520-
method = 'visit_' + type_name
521-
try:
522-
visitor = getattr(self, method)
523-
except AttributeError:
524-
pass
525-
else:
526-
import warnings
527-
warnings.warn(f"{method} is deprecated; add visit_Constant",
528-
DeprecationWarning, 2)
529-
return visitor(node)
530-
return self.generic_visit(node)
531-
532511

533512
class NodeTransformer(NodeVisitor):
534513
"""
@@ -597,142 +576,6 @@ def generic_visit(self, node):
597576
"use ast.Constant instead"
598577
)
599578

600-
601-
# If the ast module is loaded more than once, only add deprecated methods once
602-
if not hasattr(Constant, 'n'):
603-
# The following code is for backward compatibility.
604-
# It will be removed in future.
605-
606-
def _n_getter(self):
607-
"""Deprecated. Use value instead."""
608-
import warnings
609-
warnings._deprecated(
610-
"Attribute n", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14)
611-
)
612-
return self.value
613-
614-
def _n_setter(self, value):
615-
import warnings
616-
warnings._deprecated(
617-
"Attribute n", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14)
618-
)
619-
self.value = value
620-
621-
def _s_getter(self):
622-
"""Deprecated. Use value instead."""
623-
import warnings
624-
warnings._deprecated(
625-
"Attribute s", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14)
626-
)
627-
return self.value
628-
629-
def _s_setter(self, value):
630-
import warnings
631-
warnings._deprecated(
632-
"Attribute s", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14)
633-
)
634-
self.value = value
635-
636-
Constant.n = property(_n_getter, _n_setter)
637-
Constant.s = property(_s_getter, _s_setter)
638-
639-
class _ABC(type):
640-
641-
def __init__(cls, *args):
642-
cls.__doc__ = """Deprecated AST node class. Use ast.Constant instead"""
643-
644-
def __instancecheck__(cls, inst):
645-
if cls in _const_types:
646-
import warnings
647-
warnings._deprecated(
648-
f"ast.{cls.__qualname__}",
649-
message=_DEPRECATED_CLASS_MESSAGE,
650-
remove=(3, 14)
651-
)
652-
if not isinstance(inst, Constant):
653-
return False
654-
if cls in _const_types:
655-
try:
656-
value = inst.value
657-
except AttributeError:
658-
return False
659-
else:
660-
return (
661-
isinstance(value, _const_types[cls]) and
662-
not isinstance(value, _const_types_not.get(cls, ()))
663-
)
664-
return type.__instancecheck__(cls, inst)
665-
666-
def _new(cls, *args, **kwargs):
667-
for key in kwargs:
668-
if key not in cls._fields:
669-
# arbitrary keyword arguments are accepted
670-
continue
671-
pos = cls._fields.index(key)
672-
if pos < len(args):
673-
raise TypeError(f"{cls.__name__} got multiple values for argument {key!r}")
674-
if cls in _const_types:
675-
import warnings
676-
warnings._deprecated(
677-
f"ast.{cls.__qualname__}", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 14)
678-
)
679-
return Constant(*args, **kwargs)
680-
return Constant.__new__(cls, *args, **kwargs)
681-
682-
class Num(Constant, metaclass=_ABC):
683-
_fields = ('n',)
684-
__new__ = _new
685-
686-
class Str(Constant, metaclass=_ABC):
687-
_fields = ('s',)
688-
__new__ = _new
689-
690-
class Bytes(Constant, metaclass=_ABC):
691-
_fields = ('s',)
692-
__new__ = _new
693-
694-
class NameConstant(Constant, metaclass=_ABC):
695-
__new__ = _new
696-
697-
class Ellipsis(Constant, metaclass=_ABC):
698-
_fields = ()
699-
700-
def __new__(cls, *args, **kwargs):
701-
if cls is _ast_Ellipsis:
702-
import warnings
703-
warnings._deprecated(
704-
"ast.Ellipsis", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 14)
705-
)
706-
return Constant(..., *args, **kwargs)
707-
return Constant.__new__(cls, *args, **kwargs)
708-
709-
# Keep another reference to Ellipsis in the global namespace
710-
# so it can be referenced in Ellipsis.__new__
711-
# (The original "Ellipsis" name is removed from the global namespace later on)
712-
_ast_Ellipsis = Ellipsis
713-
714-
_const_types = {
715-
Num: (int, float, complex),
716-
Str: (str,),
717-
Bytes: (bytes,),
718-
NameConstant: (type(None), bool),
719-
Ellipsis: (type(...),),
720-
}
721-
_const_types_not = {
722-
Num: (bool,),
723-
}
724-
725-
_const_node_type_names = {
726-
bool: 'NameConstant', # should be before int
727-
type(None): 'NameConstant',
728-
int: 'Num',
729-
float: 'Num',
730-
complex: 'Num',
731-
str: 'Str',
732-
bytes: 'Bytes',
733-
type(...): 'Ellipsis',
734-
}
735-
736579
class slice(AST):
737580
"""Deprecated AST node class."""
738581

@@ -1884,27 +1727,12 @@ def visit_MatchOr(self, node):
18841727
self.set_precedence(_Precedence.BOR.next(), *node.patterns)
18851728
self.interleave(lambda: self.write(" | "), self.traverse, node.patterns)
18861729

1730+
18871731
def unparse(ast_obj):
18881732
unparser = _Unparser()
18891733
return unparser.visit(ast_obj)
18901734

18911735

1892-
_deprecated_globals = {
1893-
name: globals().pop(name)
1894-
for name in ('Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis')
1895-
}
1896-
1897-
def __getattr__(name):
1898-
if name in _deprecated_globals:
1899-
globals()[name] = value = _deprecated_globals[name]
1900-
import warnings
1901-
warnings._deprecated(
1902-
f"ast.{name}", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 14)
1903-
)
1904-
return value
1905-
raise AttributeError(f"module 'ast' has no attribute '{name}'")
1906-
1907-
19081736
def main():
19091737
import argparse
19101738

0 commit comments

Comments
 (0)
0