summaryrefslogtreecommitdiff
path: root/rebuilder.py
diff options
context:
space:
mode:
authorJulien Cristau <julien.cristau@logilab.fr>2014-06-10 18:48:00 +0200
committerJulien Cristau <julien.cristau@logilab.fr>2014-06-10 18:48:00 +0200
commite9ddb83591ba90c1c9ce049067ee5eb48ead1981 (patch)
tree87ea852ceae72d36186b4048622ddf8011e43a59 /rebuilder.py
parentf9a5177abbe09ef6ff704034a5f3fc9713612ddc (diff)
downloadastroid-git-e9ddb83591ba90c1c9ce049067ee5eb48ead1981.tar.gz
Handle __metaclass__ defined at the module level
According to the doc (https://docs.python.org/2/reference/datamodel.html#customizing-class-creation): The appropriate metaclass is determined by the following precedence rules: - If dict['__metaclass__'] exists, it is used. - Otherwise, if there is at least one base class, its metaclass is used (this looks for a __class__ attribute first and if not found, uses its type). - Otherwise, if a global variable named __metaclass__ exists, it is used. - Otherwise, the old-style, classic metaclass (types.ClassType) is used. The third case was not handled by node.metaclass(). Remove metaclass lookup from the rebuilder, handle it all in Class._explicit_metaclass() instead, and use that in _newstyle_impl if possible. Remove test_newstyle_and_metaclass_bad, as I think the returned value in this test is irrelevant (it's a TypeError anyway, so you can't actually build that class), and replace it with a test using nested classes. Closes issue#33
Diffstat (limited to 'rebuilder.py')
-rw-r--r--rebuilder.py20
1 files changed, 1 insertions, 19 deletions
diff --git a/rebuilder.py b/rebuilder.py
index 40a614f8..47eff50e 100644
--- a/rebuilder.py
+++ b/rebuilder.py
@@ -116,12 +116,6 @@ def _set_infos(oldnode, newnode, parent):
newnode.col_offset = oldnode.col_offset
newnode.set_line_info(newnode.last_child()) # set_line_info accepts None
-def _infer_metaclass(node):
- if isinstance(node, Name):
- return node.id
- elif isinstance(node, Attribute):
- return node.attr
-
def _create_yield_node(node, parent, rebuilder, factory):
newnode = factory()
_lineno_parent(node, newnode, parent)
@@ -137,7 +131,6 @@ class TreeRebuilder(object):
def __init__(self, manager):
self._manager = manager
self.asscontext = None
- self._metaclass = ['']
self._global_names = []
self._from_nodes = []
self._delayed_assattr = []
@@ -246,9 +239,6 @@ class TreeRebuilder(object):
meth.extra_decorators.append(newnode.value)
except (AttributeError, KeyError):
continue
- elif getattr(newnode.targets[0], 'name', None) == '__metaclass__':
- # XXX check more...
- self._metaclass[-1] = _infer_metaclass(node.value)
newnode.set_line_info(newnode.last_child())
return newnode
@@ -321,7 +311,6 @@ class TreeRebuilder(object):
def visit_class(self, node, parent):
"""visit a Class node to become astroid"""
- self._metaclass.append(self._metaclass[-1])
newnode = new.Class(node.name, None)
_lineno_parent(node, newnode, parent)
_init_set_doc(node, newnode)
@@ -330,14 +319,6 @@ class TreeRebuilder(object):
if 'decorator_list' in node._fields and node.decorator_list:# py >= 2.6
newnode.decorators = self.visit_decorators(node, newnode)
newnode.set_line_info(newnode.last_child())
- metaclass = self._metaclass.pop()
- if PY3K:
- newnode._newstyle = True
- else:
- if not newnode.bases:
- # no base classes, detect new / style old style according to
- # current scope
- newnode._newstyle = metaclass in ('type', 'ABCMeta')
newnode.parent.frame().set_local(newnode.name, newnode)
return newnode
@@ -942,6 +923,7 @@ class TreeRebuilder3k(TreeRebuilder):
def visit_class(self, node, parent):
newnode = super(TreeRebuilder3k, self).visit_class(node, parent)
+ newnode._newstyle = True
for keyword in node.keywords:
if keyword.arg == 'metaclass':
newnode._metaclass = self.visit(keyword, newnode).value