Ticket #11342: trac11342-attribute_error_message.rebased.patch

File trac11342-attribute_error_message.rebased.patch, 7.1 KB (added by SimonKing, 9 years ago)

Only apply this patch. Make attribute access faster on elements and parents: Create the error message only when needed

  • sage/structure/element.pyx

    # HG changeset patch
    # User Simon King <simon.king@uni-jena.de>
    # Date 1306046266 -7200
    # Node ID 127fe1e0c7879abdeb7ef1b5dbf1c33737b7cede
    # Parent  ab5b5042cc4760a913211de94f86c247f0a3676a
    #11342: Make getattr faster on elements and parents
    
    diff --git a/sage/structure/element.pyx b/sage/structure/element.pyx
    a b  
    187187from types import MethodType
    188188
    189189from sage.categories.category   import Category
    190 from sage.structure.parent      cimport Parent, raise_attribute_error
     190from sage.structure.parent      cimport Parent, AttributeErrorMessage
    191191from sage.structure.parent      import is_extension_type, getattr_from_other_class
    192192from sage.misc.lazy_format      import LazyFormat
    193193
     
    266266        return self
    267267
    268268
    269     def __getattr__(self, name):
     269    def __getattr__(self, str name):
    270270        """
    271271        Let cat be the category of the parent of ``self``.  This
    272272        method emulates ``self`` being an instance of both ``Element``
     
    323323            AttributeError: 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint' object has no attribute '__foo'
    324324
    325325        """
    326         if name.startswith('__') and not name.endswith('_'):
    327             raise_attribute_error(self, name)
    328         return getattr_from_other_class(self, self.parent().category().element_class, name)
     326        if (name.startswith('__') and not name.endswith('_')) or self._parent._category is None:
     327            raise AttributeError, AttributeErrorMessage(self, name)
     328        return getattr_from_other_class(self, self._parent._category.element_class, name)
    329329
    330330    def __dir__(self):
    331331        """
  • sage/structure/parent.pxd

    diff --git a/sage/structure/parent.pxd b/sage/structure/parent.pxd
    a b  
    66#                  http://www.gnu.org/licenses/
    77###############################################################################
    88
    9 #cimport sage.categories.object
    109cimport sage.structure.category_object
    1110
    12 cdef inline raise_attribute_error(self, name)
     11cdef class AttributeErrorMessage:
     12    cdef type cls
     13    cdef str name
    1314
    1415cdef class Parent(category_object.CategoryObject):
    1516
  • sage/structure/parent.pyx

    diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
    a b  
    149149        False
    150150    """
    151151    # Robert B claims that this should be robust
    152     return hasattr(cls, "__dictoffset__") and cls.__dictoffset__ == 0
     152    try:
     153        return cls.__dictoffset__ == 0
     154    except AttributeError:
     155        pass
     156    return False
    153157
    154158class A(object):
    155159    pass
    156160methodwrapper = type(A.__call__)
    157161
    158 cdef inline raise_attribute_error(self, name):
     162cdef class AttributeErrorMessage:
    159163    """
    160     Tries to emulate the standard Python AttributeError exception
     164    Tries to emulate the standard Python ``AttributeError`` message.
     165
     166    NOTE:
     167
     168    The typical fate of an attribute error is being caught. Hence,
     169    under normal circumstances, nobody will ever see the error
     170    message. The idea for this class is to provide an object that
     171    is fast to create and whose string representation is an attribute
     172    error's message. That string representation is only created if
     173    someone wants to see it.
    161174
    162175    EXAMPLES::
    163176
     
    169182        Traceback (most recent call last):
    170183        ...
    171184        AttributeError: 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint' object has no attribute 'bla'
     185        sage: from sage.structure.parent import AttributeErrorMessage
     186        sage: AttributeErrorMessage(int(1),'bla')
     187        'int' object has no attribute 'bla'
     188
     189    AUTHOR:
     190
     191    - Simon King (2011-05-21)
    172192    """
    173     cls = type(self)
    174     if is_extension_type(cls):
    175         raise AttributeError, "'%s.%s' object has no attribute '%s'"%(cls.__module__, cls.__name__, name)
    176     else:
    177         raise AttributeError, "'%s' object has no attribute '%s'"%(cls.__name__, name)
     193#    raise AttributeError, AttributeErrorMessage(self,name)
     194    def __init__(self, P,str name):
     195        """
     196        INPUT:
    178197
    179 def getattr_from_other_class(self, cls, name):
     198        - ``P``, any object
     199        - ``name``, a string
     200
     201        TEST::
     202
     203            sage: from sage.structure.parent import AttributeErrorMessage
     204            sage: AttributeErrorMessage(int(1),'bla')
     205            'int' object has no attribute 'bla'
     206
     207        """
     208        self.cls = type(P)
     209        self.name = name
     210    def __repr__(self):
     211        """
     212        TEST::
     213
     214            sage: from sage.structure.parent import AttributeErrorMessage
     215            sage: AttributeErrorMessage(int(1),'bla')
     216            'int' object has no attribute 'bla'
     217
     218        """
     219        cdef int dictoff
     220        try:
     221            dictoff = self.cls.__dictoffset__
     222        except AttributeError:
     223            return "'"+self.cls.__name__+"' object has no attribute '"+self.name+"'"
     224        if dictoff:
     225            return "'"+self.cls.__name__+"' object has no attribute '"+self.name+"'"
     226        return repr(self.cls)[6:-1] + " object has no attribute '"+self.name+"'"
     227
     228
     229def getattr_from_other_class(self, cls, str name):
    180230    """
    181231    INPUT::
    182232
     
    269319        ...
    270320        AttributeError: 'sage.rings.integer.Integer' object has no attribute '__call__'
    271321    """
    272     if isinstance(self, cls):
    273         raise_attribute_error(self, name)
     322    if PY_TYPE_CHECK(self, cls):
     323        raise AttributeError, AttributeErrorMessage(self, name)
    274324    try:
    275325        attribute = getattr(cls, name)
    276326    except AttributeError:
    277         raise_attribute_error(self, name)
    278     if isinstance(attribute, methodwrapper):
    279         raise_attribute_error(self, name)
     327        raise AttributeError, AttributeErrorMessage(self, name)
     328    if PY_TYPE_CHECK(attribute, methodwrapper):
     329        raise AttributeError, AttributeErrorMessage(self, name)
    280330    try:
    281331        getter = attribute.__get__
    282332    except AttributeError:
     
    289339        return getter(self, cls)
    290340    except TypeError:
    291341        pass
    292     raise_attribute_error(self, name)
     342    raise AttributeError, AttributeErrorMessage(self, name)
    293343
    294344def dir_with_other_class(self, cls):
    295345    r"""
     
    696746            self._convert_from_hash = {}
    697747            self._embedding = None
    698748
    699     def __getattr__(self, name):
     749    def __getattr__(self, str name):
    700750        """
    701751        Let cat be the category of ``self``. This method emulates
    702752        ``self`` being an instance of both ``Parent`` and
     
    756806            AttributeError: 'sage.structure.parent.Parent' object has no attribute '__foo'
    757807
    758808        """
    759         if name.startswith('__') and not name.endswith('_'):
    760             raise_attribute_error(self, name)
    761         if self._is_category_initialized():
    762             return getattr_from_other_class(self, self.category().parent_class, name)
    763         else:
    764             raise_attribute_error(self, name)
     809        if (name.startswith('__') and not name.endswith('_')) or self._category is None:
     810            raise AttributeError, AttributeErrorMessage(self, name)
     811        return getattr_from_other_class(self, self._category.parent_class, name)
    765812
    766813    def __dir__(self):
    767814        """