diff options
author | Julien Cristau <julien.cristau@logilab.fr> | 2014-06-10 18:48:00 +0200 |
---|---|---|
committer | Julien Cristau <julien.cristau@logilab.fr> | 2014-06-10 18:48:00 +0200 |
commit | e9ddb83591ba90c1c9ce049067ee5eb48ead1981 (patch) | |
tree | 87ea852ceae72d36186b4048622ddf8011e43a59 /rebuilder.py | |
parent | f9a5177abbe09ef6ff704034a5f3fc9713612ddc (diff) | |
download | astroid-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.py | 20 |
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 |