Skip to content

Commit

Permalink
bpo-32892: Use ast.Constant instead of specific constant AST types. (G…
Browse files Browse the repository at this point in the history
  • Loading branch information
serhiy-storchaka committed Sep 27, 2018
1 parent a94ee12 commit 3f22811
Show file tree
Hide file tree
Showing 20 changed files with 337 additions and 678 deletions.
15 changes: 11 additions & 4 deletions Doc/library/ast.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,25 @@ Node classes

node = ast.UnaryOp()
node.op = ast.USub()
node.operand = ast.Num()
node.operand.n = 5
node.operand = ast.Constant()
node.operand.value = 5
node.operand.lineno = 0
node.operand.col_offset = 0
node.lineno = 0
node.col_offset = 0

or the more compact ::

node = ast.UnaryOp(ast.USub(), ast.Num(5, lineno=0, col_offset=0),
node = ast.UnaryOp(ast.USub(), ast.Constant(5, lineno=0, col_offset=0),
lineno=0, col_offset=0)

.. deprecated:: 3.8

Class :class:`ast.Constant` is now used for all constants. Old classes
:class:`ast.Num`, :class:`ast.Str`, :class:`ast.Bytes`,
:class:`ast.NameConstant` and :class:`ast.Ellipsis` are still available,
but they will be removed in future Python releases.


.. _abstract-grammar:

Expand Down Expand Up @@ -239,7 +246,7 @@ and classes for traversing abstract syntax trees:
def visit_Name(self, node):
return copy_location(Subscript(
value=Name(id='data', ctx=Load()),
slice=Index(value=Str(s=node.id)),
slice=Index(value=Constant(value=node.id)),
ctx=node.ctx
), node)

Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.8.rst
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ Deprecated

(Contributed by Berker Peksag in :issue:`9372`.)

* :mod:`ast` classes ``Num``, ``Str``, ``Bytes``, ``NameConstant`` and
``Ellipsis`` are considered deprecated and will be removed in future Python
versions. :class:`~ast.Constant` should be used instead.
(Contributed by Serhiy Storchaka in :issue:`32892`.)


Removed
=======
Expand Down
36 changes: 4 additions & 32 deletions Include/Python-ast.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 64 additions & 9 deletions Lib/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,8 @@ def literal_eval(node_or_string):
node_or_string = node_or_string.body
def _convert_num(node):
if isinstance(node, Constant):
if isinstance(node.value, (int, float, complex)):
if type(node.value) in (int, float, complex):
return node.value
elif isinstance(node, Num):
return node.n
raise ValueError('malformed node or string: ' + repr(node))
def _convert_signed_num(node):
if isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):
Expand All @@ -64,10 +62,6 @@ def _convert_signed_num(node):
def _convert(node):
if isinstance(node, Constant):
return node.value
elif isinstance(node, (Str, Bytes)):
return node.s
elif isinstance(node, Num):
return node.n
elif isinstance(node, Tuple):
return tuple(map(_convert, node.elts))
elif isinstance(node, List):
Expand All @@ -77,8 +71,6 @@ def _convert(node):
elif isinstance(node, Dict):
return dict(zip(map(_convert, node.keys),
map(_convert, node.values)))
elif isinstance(node, NameConstant):
return node.value
elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):
left = _convert_signed_num(node.left)
right = _convert_num(node.right)
Expand Down Expand Up @@ -329,3 +321,66 @@ def generic_visit(self, node):
else:
setattr(node, field, new_node)
return node


# The following code is for backward compatibility.
# It will be removed in future.

def _getter(self):
return self.value

def _setter(self, value):
self.value = value

Constant.n = property(_getter, _setter)
Constant.s = property(_getter, _setter)

class _ABC(type):

def __instancecheck__(cls, inst):
if not isinstance(inst, Constant):
return False
if cls in _const_types:
try:
value = inst.value
except AttributeError:
return False
else:
return type(value) in _const_types[cls]
return type.__instancecheck__(cls, inst)

def _new(cls, *args, **kwargs):
if cls in _const_types:
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 Ellipsis:
return Constant(..., *args, **kwargs)
return Constant.__new__(cls, *args, **kwargs)

_const_types = {
Num: (int, float, complex),
Str: (str,),
Bytes: (bytes,),
NameConstant: (type(None), bool),
Ellipsis: (type(...),),
}
10 changes: 2 additions & 8 deletions Lib/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -2005,14 +2005,8 @@ def wrap_value(s):
except NameError:
raise RuntimeError()

if isinstance(value, str):
return ast.Str(value)
if isinstance(value, (int, float)):
return ast.Num(value)
if isinstance(value, bytes):
return ast.Bytes(value)
if value in (True, False, None):
return ast.NameConstant(value)
if isinstance(value, (str, int, float, bytes, bool, type(None))):
return ast.Constant(value)
raise RuntimeError()

class RewriteSymbolics(ast.NodeTransformer):
Expand Down
Loading

0 comments on commit 3f22811

Please sign in to comment.