Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-32892: Use ast.Constant instead of specific constant AST types. #9445

Merged
merged 8 commits into from
Sep 27, 2018
Merged
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 @@ -223,6 +223,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`.)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we mention the deprecation in ast.rst as well? Maybe near:
https://docs.python.org/dev/library/ast.html#abstract-grammar

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I didn't know good place for this, you have suggested me one.



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