Python decorators for use in Sage.
AUTHORS:
This function allows a decorator to have default arguments.
Normally, a decorator can be called with or without arguments. However, the two cases call for different types of return values. If a decorator is called with no parentheses, it should be run directly on the function. However, if a decorator is called with parentheses (i.e., arguments), then it should return a function that is then in turn called with the defined function as an argument.
This decorator allows us to have these default arguments without worrying about the return type.
EXAMPLES:
sage: from sage.misc.decorators import decorator_defaults
sage: @decorator_defaults
... def my_decorator(f,*args,**kwds):
... print kwds
... print args
... print f.__name__
...
sage: @my_decorator
... def my_fun(a,b):
... return a,b
...
{}
()
my_fun
sage: @my_decorator(3,4,c=1,d=2)
... def my_fun(a,b):
... return a,b
...
{'c': 1, 'd': 2}
(3, 4)
my_fun
Bases: object
A decorator for functions which allows for a hack that makes the function behave like an infix operator.
This decorator exists as a convenience for interactive use.
EXAMPLES:
An infix dot product operator:
sage: def dot(a,b): return a.dot_product(b)
sage: dot=infix_operator('multiply')(dot)
sage: u=vector([1,2,3])
sage: v=vector([5,4,3])
sage: u *dot* v
22
An infix element-wise addition operator:
sage: def eadd(a,b):
... return a.parent([i+j for i,j in zip(a,b)])
sage: eadd=infix_operator('add')(eadd)
sage: u=vector([1,2,3])
sage: v=vector([5,4,3])
sage: u +eadd+ v
(6, 6, 6)
sage: 2*u +eadd+ v
(7, 8, 9)
A hack to simulate a postfix operator:
sage: def thendo(a,b): return b(a)
sage: thendo=infix_operator('or')(thendo)
sage: x |thendo| cos |thendo| (lambda x: x^2)
cos(x)^2
Bases: object
A decorator for functions which allows for default options to be set and reset by the end user. Additionally, if one needs to, one can get at the original keyword arguments passed into the decorator.
TESTS:
sage: from sage.misc.decorators import options
sage: o = options(rgbcolor=(0,0,1))
sage: o.options
{'rgbcolor': (0, 0, 1)}
sage: o = options(rgbcolor=(0,0,1), __original_opts=True)
sage: o.original_opts
True
sage: loads(dumps(o)).options
{'rgbcolor': (0, 0, 1)}
Demonstrate that the introspected argument specification of the wrapped function is updated (see trac ticket #9976):
sage: from sage.misc.decorators import options
sage: o = options(rgbcolor=(0,0,1))
sage: def f(*args, **kwds): print args, list(sorted(kwds.items()))
sage: f1 = o(f)
sage: from sage.misc.sageinspect import sage_getargspec
sage: sage_getargspec(f1)
ArgSpec(args=['rgbcolor'], varargs='args', keywords='kwds', defaults=((0, 0, 1),))
Bases: object
A decorator which renames keyword arguments and optionally deprecates the new keyword.
INPUT:
EXAMPLES:
sage: from sage.misc.decorators import rename_keyword
sage: r = rename_keyword(color='rgbcolor')
sage: r.renames
{'color': 'rgbcolor'}
sage: loads(dumps(r)).renames
{'color': 'rgbcolor'}
To deprecate an old keyword:
sage: r = rename_keyword(deprecation=13109, color='rgbcolor')
Decorator factory which should be used in decorators for making sure that meta-information on the decorated callables are retained through the decorator, such that the introspection functions of sage.misc.sageinspect retrieves them correctly. This includes documentation string, source, and argument specification. This is an extension of the Python standard library decorator functools.wraps.
That the argument specification is retained from the decorated functions implies, that if one uses sage_wraps in a decorator which intentionally changes the argument specification, one should add this information to the special attribute _sage_argspec_ of the wrapping function (for an example, see e.g. @options decorator in this module).
EXAMPLES:
Demonstrate that documentation string and source are retained from the decorated function:
sage: def square(f):
... @sage_wraps(f)
... def new_f(x):
... return f(x)*f(x)
... return new_f
sage: @square
... def g(x):
... "My little function"
... return x
sage: g(2)
4
sage: g(x)
x^2
sage: g.__doc__
'My little function'
sage: from sage.misc.sageinspect import sage_getsource, sage_getsourcelines, sage_getfile
sage: sage_getsource(g)
'@square...def g(x)...'
Demonstrate that the argument description are retained from the decorated function through the special method (when left unchanged) (see trac ticket #9976):
sage: def diff_arg_dec(f):
... @sage_wraps(f)
... def new_f(y, some_def_arg=2):
... return f(y+some_def_arg)
... return new_f
sage: @diff_arg_dec
... def g(x):
... return x
sage: g(1)
3
sage: g(1, some_def_arg=4)
5
sage: from sage.misc.sageinspect import sage_getargspec
sage: sage_getargspec(g)
ArgSpec(args=['x'], varargs=None, keywords=None, defaults=None)
Demonstrate that it correctly gets the source lines and the source file, which is essential for interactive code edition; note that we do not test the line numbers, as they may easily change:
sage: P.<x,y> = QQ[]
sage: I = P*[x,y]
sage: sage_getfile(I.interreduced_basis)
'...sage/rings/polynomial/multi_polynomial_ideal.py'
sage: sage_getsourcelines(I.interreduced_basis)
([' @singular_standard_options\n',
' @libsingular_standard_options\n',
' def interreduced_basis(self):\n',
...
' return ret\n'], ...)
Demonstrate that sage_wraps works for non-function callables (trac ticket #9919):
sage: def square_for_met(f):
... @sage_wraps(f)
... def new_f(self, x):
... return f(self,x)*f(self,x)
... return new_f
sage: class T:
... @square_for_met
... def g(self, x):
... "My little method"
... return x
sage: t = T()
sage: t.g(2)
4
sage: t.g.__doc__
'My little method'
The bug described in trac ticket #11734 is fixed:
sage: def square(f):
... @sage_wraps(f)
... def new_f(x):
... return f(x)*f(x)
... return new_f
sage: f = lambda x:x^2
sage: g = square(f)
sage: g(3) # this line used to fail for some people if these command were manually entered on the sage prompt
81
A decorator generator that returns a decorator that in turn returns a specialized function for function f. In other words, it returns a function that acts like f with arguments *args and **kwargs supplied.
INPUT:
OUTPUT:
EXAMPLES:
sage: f = specialize(5)(lambda x, y: x+y)
sage: f(10)
15
sage: f(5)
10
sage: @specialize("Bon Voyage")
... def greet(greeting, name):
... print "{0}, {1}!".format(greeting, name)
sage: greet("Monsieur Jean Valjean")
Bon Voyage, Monsieur Jean Valjean!
sage: greet(name = 'Javert')
Bon Voyage, Javert!
Bases: object
A decorator for functions which collects all keywords starting with name+'_' and collects them into a dictionary which will be passed on to the wrapped function as a dictionary called name_options.
The keyword arguments passed into the constructor are taken to be default for the name_options dictionary.
EXAMPLES:
sage: from sage.misc.decorators import suboptions
sage: s = suboptions('arrow', size=2)
sage: s.name
'arrow_'
sage: s.options
{'size': 2}