Commit b3c67d1d authored by Robert Bradshaw's avatar Robert Bradshaw

merge __getattribut__ code

parents 45f2a56e 6b56ec73
......@@ -666,7 +666,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_ass_subscript_function(scope, code)
if scope.defines_any(["__setslice__", "__delslice__"]):
self.generate_ass_slice_function(scope, code)
if scope.defines_any(["__getattr__"]):
if scope.defines_any(["__getattr__","__getattribute__"]):
self.generate_getattro_function(scope, code)
if scope.defines_any(["__setattr__", "__delattr__"]):
self.generate_setattro_function(scope, code)
......@@ -1030,27 +1030,47 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"}")
def generate_getattro_function(self, scope, code):
# First try to get the attribute using PyObject_GenericGetAttr.
# If that raises an AttributeError, call the user's __getattr__
# method.
entry = scope.lookup_here("__getattr__")
# First try to get the attribute using __getattribute__, if defined, or
# PyObject_GenericGetAttr.
#
# If that raises an AttributeError, call the __getattr__ if defined.
#
# In both cases, defined can be in this class, or any base class.
def lookup_here_or_base(n,type=None):
# Recursive lookup
if type is None:
type = scope.parent_type
r = type.scope.lookup_here(n)
if r is None and \
type.base_type is not None:
return lookup_here_or_base(n,type.base_type)
else:
return r
getattr_entry = lookup_here_or_base("__getattr__")
getattribute_entry = lookup_here_or_base("__getattribute__")
code.putln("")
code.putln(
"static PyObject *%s(PyObject *o, PyObject *n) {"
% scope.mangle_internal("tp_getattro"))
code.putln(
if getattribute_entry is not None:
code.putln(
"PyObject *v = %s(o, n);" %
getattribute_entry.func_cname)
else:
code.putln(
"PyObject *v = PyObject_GenericGetAttr(o, n);")
code.putln(
if getattr_entry is not None:
code.putln(
"if (!v && PyErr_ExceptionMatches(PyExc_AttributeError)) {")
code.putln(
"PyErr_Clear();")
code.putln(
"v = %s(o, n);" %
entry.func_cname)
code.putln(
code.putln(
"PyErr_Clear();")
code.putln(
"v = %s(o, n);" %
getattr_entry.func_cname)
code.putln(
"}")
code.putln(
"return v;")
"return v;")
code.putln(
"}")
......
......@@ -610,7 +610,7 @@ slot_table = (
MethodSlot(callfunc, "tp_call", "__call__"),
MethodSlot(reprfunc, "tp_str", "__str__"),
SyntheticSlot("tp_getattro", ["__getattr__"], "0"), #"PyObject_GenericGetAttr"),
SyntheticSlot("tp_getattro", ["__getattr__","__getattribute__"], "0"), #"PyObject_GenericGetAttr"),
SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"), #"PyObject_GenericSetAttr"),
SuiteSlot(PyBufferProcs, "PyBufferProcs", "tp_as_buffer"),
......
__doc__ = """
__getattribute__ and __getattr__ special methods for a single class.
>>> a = just_getattribute()
>>> a.bar
'bar'
>>> a.invalid
Traceback (most recent call last):
AttributeError
>>> a = just_getattr()
>>> a.foo
10
>>> a.bar
'bar'
>>> a.invalid
Traceback (most recent call last):
AttributeError
>>> a = both()
>>> a.foo
10
>>> a.bar
'bar'
>>> a.invalid
Traceback (most recent call last):
AttributeError
"""
cdef class just_getattribute:
def __getattribute__(self,n):
if n == 'bar':
return n
else:
raise AttributeError
cdef class just_getattr:
cdef readonly int foo
def __init__(self):
self.foo = 10
def __getattr__(self,n):
if n == 'bar':
return n
else:
raise AttributeError
cdef class both:
cdef readonly int foo
def __init__(self):
self.foo = 10
def __getattribute__(self,n):
if n == 'foo':
return self.foo
else:
raise AttributeError
def __getattr__(self,n):
if n == 'bar':
return n
else:
raise AttributeError
__doc__ = """
__getattribute__ and __getattr__ special methods and subclasses.
getattr does not override members.
>>> a = getattr_boring()
>>> a.boring_member
10
>>> a.resolved_by
'getattr_boring'
getattribute does.
>>> a = getattribute_boring()
>>> a.boring_member
Traceback (most recent call last):
AttributeError
>>> a.resolved_by
'getattribute_boring'
Is inherited.
>>> a = boring_boring_getattribute()
>>> a.boring_getattribute_member
Traceback (most recent call last):
AttributeError
>>> a.boring_boring_getattribute_member
Traceback (most recent call last):
AttributeError
>>> a.resolved_by
'_getattribute'
__getattribute__ is always tried first, then __getattr__, regardless of where
in the inheritance hiarchy they came from.
>>> a = getattribute_boring_boring_getattr()
>>> a.foo
Traceback (most recent call last):
AttributeError
>>> a.resolved_by
'getattribute_boring_boring_getattr'
>>> a.getattribute_boring_boring_getattr
True
>>> a._getattr
True
>>> a = getattr_boring_boring_getattribute()
>>> a.foo
Traceback (most recent call last):
AttributeError
>>> a.resolved_by
'_getattribute'
>>> a.getattr_boring_boring_getattribute
True
>>> a._getattribute
True
"""
cdef class boring:
cdef readonly int boring_member
def __init__(self):
self.boring_member = 10
cdef class getattr_boring(boring):
def __getattr__(self,n):
if n == 'resolved_by':
return 'getattr_boring'
elif n == 'getattr_boring':
return True
else:
raise AttributeError
cdef class getattribute_boring(boring):
def __getattribute__(self,n):
if n == 'resolved_by':
return 'getattribute_boring'
elif n == 'getattribute_boring':
return True
else:
raise AttributeError
cdef class _getattr:
def __getattr__(self,n):
if n == 'resolved_by':
return '_getattr'
elif n == '_getattr':
return True
else:
raise AttributeError
cdef class _getattribute(boring):
def __getattribute__(self,n):
if n == 'resolved_by':
return '_getattribute'
elif n == '_getattribute':
return True
else:
raise AttributeError
cdef class boring_getattribute(_getattribute):
cdef readonly int boring_getattribute_member
cdef class boring_boring_getattribute(boring_getattribute):
cdef readonly int boring_boring_getattribute_member
cdef class boring_getattr(_getattr):
cdef readonly int boring_getattr_member
cdef class boring_boring_getattr(boring_getattr):
cdef readonly int boring_boring_getattr_member
cdef class getattribute_boring_boring_getattr(boring_boring_getattr):
def __getattribute__(self,n):
if n == 'resolved_by':
return 'getattribute_boring_boring_getattr'
elif n == 'getattribute_boring_boring_getattr':
return True
else:
raise AttributeError
cdef class getattr_boring_boring_getattribute(boring_boring_getattribute):
def __getattr__(self,n):
if n == 'resolved_by':
return 'getattr_boring_boring_getattribute'
elif n == 'getattr_boring_boring_getattribute':
return True
else:
raise AttributeError
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment