summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2019-08-26 10:13:19 +0300
committerGitHub <noreply@github.com>2019-08-26 10:13:19 +0300
commitc3ea41e9bf100a5396b851488c3efe208e5e2179 (patch)
tree5e30febe4e132ed33968e96ca81aeb043e33387a
parent44cd86bbdddb1f7b05deba2c1986a1e98f992429 (diff)
downloadcpython-git-c3ea41e9bf100a5396b851488c3efe208e5e2179.tar.gz
bpo-36917: Add default implementation of ast.NodeVisitor.visit_Constant(). (GH-15490)
It emits a deprecation warning and calls corresponding method visit_Num(), visit_Str(), etc.
-rw-r--r--Doc/library/ast.rst7
-rw-r--r--Doc/whatsnew/3.8.rst7
-rw-r--r--Lib/ast.py31
-rw-r--r--Lib/test/test_ast.py51
-rw-r--r--Misc/NEWS.d/next/Library/2019-08-25-14-56-42.bpo-36917.GBxdw2.rst3
5 files changed, 99 insertions, 0 deletions
diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst
index 1e71838258..3d2c420bc2 100644
--- a/Doc/library/ast.rst
+++ b/Doc/library/ast.rst
@@ -275,6 +275,13 @@ and classes for traversing abstract syntax trees:
during traversal. For this a special visitor exists
(:class:`NodeTransformer`) that allows modifications.
+ .. deprecated:: 3.8
+
+ Methods :meth:`visit_Num`, :meth:`visit_Str`, :meth:`visit_Bytes`,
+ :meth:`visit_NameConstant` and :meth:`visit_Ellipsis` are deprecated
+ now and will not be called in future Python versions. Add the
+ :meth:`visit_Constant` method to handle all constant nodes.
+
.. class:: NodeTransformer()
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 0294e9a083..cd31cf6db6 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -1360,6 +1360,13 @@ Deprecated
versions. :class:`~ast.Constant` should be used instead.
(Contributed by Serhiy Storchaka in :issue:`32892`.)
+* :class:`ast.NodeVisitor` methods ``visit_Num()``, ``visit_Str()``,
+ ``visit_Bytes()``, ``visit_NameConstant()`` and ``visit_Ellipsis()`` are
+ deprecated now and will not be called in future Python versions.
+ Add the :meth:`~ast.NodeVisitor.visit_Constant` method to handle all
+ constant nodes.
+ (Contributed by Serhiy Storchaka in :issue:`36917`.)
+
* The following functions and methods are deprecated in the :mod:`gettext`
module: :func:`~gettext.lgettext`, :func:`~gettext.ldgettext`,
:func:`~gettext.lngettext` and :func:`~gettext.ldngettext`.
diff --git a/Lib/ast.py b/Lib/ast.py
index ffeba179e5..1e639d11fe 100644
--- a/Lib/ast.py
+++ b/Lib/ast.py
@@ -360,6 +360,27 @@ 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):
"""
@@ -487,3 +508,13 @@ _const_types = {
_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',
+}
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index f35d9e6f54..3d12397ef6 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -3,6 +3,7 @@ import dis
import os
import sys
import unittest
+import warnings
import weakref
from textwrap import dedent
@@ -1662,6 +1663,56 @@ class EndPositionTests(unittest.TestCase):
self.assertEqual(ast.get_source_segment(s, cdef.body[0], padded=True), s_method)
+class NodeVisitorTests(unittest.TestCase):
+ def test_old_constant_nodes(self):
+ class Visitor(ast.NodeVisitor):
+ 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',
+ 'visit_Num is deprecated; add visit_Constant',
+ 'visit_Num is deprecated; add visit_Constant',
+ 'visit_Str is deprecated; add visit_Constant',
+ 'visit_Bytes is deprecated; add visit_Constant',
+ 'visit_NameConstant is deprecated; add visit_Constant',
+ 'visit_NameConstant is deprecated; add visit_Constant',
+ 'visit_Ellipsis is deprecated; add visit_Constant',
+ ])
+
+
def main():
if __name__ != '__main__':
return
diff --git a/Misc/NEWS.d/next/Library/2019-08-25-14-56-42.bpo-36917.GBxdw2.rst b/Misc/NEWS.d/next/Library/2019-08-25-14-56-42.bpo-36917.GBxdw2.rst
new file mode 100644
index 0000000000..3509a7530b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-08-25-14-56-42.bpo-36917.GBxdw2.rst
@@ -0,0 +1,3 @@
+Add default implementation of the :meth:`ast.NodeVisitor.visit_Constant`
+method which emits a deprecation warning and calls corresponding methody
+``visit_Num()``, ``visit_Str()``, etc.