Ticket #14524: trac14524-immutability_decorators.patch

File trac14524-immutability_decorators.patch, 5.0 KB (added by SimonKing, 9 years ago)
  • sage/misc/decorators.py

    # HG changeset patch
    # User Simon King <simon.king@uni-jena.de>
    # Date 1367824644 -7200
    # Node ID c2c82f01b133adc84830765b2bb7499223c95b30
    # Parent  1ddd56f1ce4b9722752064741003a9a540d74abc
    #14524: Decorator for methods requiring mutability or immutability
    
    diff --git a/sage/misc/decorators.py b/sage/misc/decorators.py
    a b  
    9292          '        return ret\n'], ...)
    9393
    9494    Demonstrate that sage_wraps works for non-function callables
    95     (Trac 9919)::
     95    (:trac:`9919`)::
    9696
    9797        sage: def square_for_met(f):
    9898        ...     @sage_wraps(f)
     
    110110        sage: t.g.__doc__
    111111        'My little method'
    112112
    113     The bug described in #11734 is fixed::
     113    The bug described in :trac:`11734` is fixed::
    114114
    115115        sage: def square(f):
    116116        ...     @sage_wraps(f)
     
    121121        sage: g = square(f)
    122122        sage: g(3) # this line used to fail for some people if these command were manually entered on the sage prompt
    123123        81
     124
    124125    """
    125126    #TRAC 9919: Workaround for bug in @update_wrapper when used with
    126127    #non-function callables.
  • sage/structure/mutability.pxd

    diff --git a/sage/structure/mutability.pxd b/sage/structure/mutability.pxd
    a b  
    1313##########################################################################
    1414
    1515cdef class Mutability:
    16     cdef bint _is_immutable
     16    cdef public bint _is_immutable
    1717    cdef _require_mutable_cdef(self)
  • sage/structure/mutability.pyx

    diff --git a/sage/structure/mutability.pyx b/sage/structure/mutability.pyx
    a b  
    7171    def __reduce__(self):
    7272        return Mutability, (self._is_immutable, )
    7373   
     74#################################################################################
     75## Method decorators for mutating methods resp. methods that assume immutability
     76from sage.misc.decorators import sage_wraps
     77
     78def require_mutable(f):
     79    """
     80    A decorator that requires mutability for a method to be called.
     81
     82    EXAMPLES::
     83
     84        sage: from sage.structure.mutability import require_mutable, require_immutable
     85        sage: class A:
     86        ...    def __init__(self, val):
     87        ...        self._m = val
     88        ...    @require_mutable
     89        ...    def change(self, new_val):
     90        ...        'change self'
     91        ...        self._m = new_val
     92        ...    @require_immutable
     93        ...    def __hash__(self):
     94        ...        'implement hash'
     95        ...        return hash(self._m)
     96        sage: a = A(5)
     97        sage: a.change(6)
     98        sage: hash(a)
     99        Traceback (most recent call last):
     100        ...
     101        ValueError: <type 'instance'> instance is mutable, <function __hash__ at ...> must not be called
     102        sage: a._is_immutable = True
     103        sage: hash(a)
     104        6
     105        sage: a.change(7)   # indirect doctest
     106        Traceback (most recent call last):
     107        ...
     108        ValueError: <type 'instance'> instance is immutable, <function change at ...> must not be called
     109        sage: from sage.misc.sageinspect import sage_getdoc
     110        sage: print sage_getdoc(a.change)
     111        change self
     112
     113    AUTHORS:
     114
     115    - Simon King <simon.king@uni-jena.de>
     116    """
     117    @sage_wraps(f)
     118    def new_f(self, *args,**kwds):
     119        if getattr(self,'_is_immutable',False):
     120            raise ValueError("%s instance is immutable, %s must not be called"%(type(self), repr(f)))
     121        return f(self, *args,**kwds)
     122    return new_f
     123
     124def require_immutable(f):
     125    """
     126    A decorator that requires mutability for a method to be called.
     127
     128    EXAMPLES::
     129
     130        sage: from sage.structure.mutability import require_mutable, require_immutable
     131        sage: class A:
     132        ...    def __init__(self, val):
     133        ...        self._m = val
     134        ...    @require_mutable
     135        ...    def change(self, new_val):
     136        ...        'change self'
     137        ...        self._m = new_val
     138        ...    @require_immutable
     139        ...    def __hash__(self):
     140        ...        'implement hash'
     141        ...        return hash(self._m)
     142        sage: a = A(5)
     143        sage: a.change(6)
     144        sage: hash(a)   # indirect doctest
     145        Traceback (most recent call last):
     146        ...
     147        ValueError: <type 'instance'> instance is mutable, <function __hash__ at ...> must not be called
     148        sage: a._is_immutable = True
     149        sage: hash(a)
     150        6
     151        sage: a.change(7)
     152        Traceback (most recent call last):
     153        ...
     154        ValueError: <type 'instance'> instance is immutable, <function change at ...> must not be called
     155        sage: from sage.misc.sageinspect import sage_getdoc
     156        sage: print sage_getdoc(a.__hash__)
     157        implement hash
     158
     159    AUTHORS:
     160
     161    - Simon King <simon.king@uni-jena.de>
     162    """
     163    @sage_wraps(f)
     164    def new_f(self, *args,**kwds):
     165        if not getattr(self,'_is_immutable',False):
     166            raise ValueError("%s instance is mutable, %s must not be called"%(type(self), repr(f)))
     167        return f(self, *args,**kwds)
     168    return new_f