Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

"""Useful utility decorators. """ 

 

from __future__ import print_function, division 

 

import sys 

import types 

import inspect 

 

from functools import update_wrapper 

 

from sympy.core.decorators import wraps 

from sympy.core.compatibility import class_types, get_function_globals, get_function_name, iterable 

 

def threaded_factory(func, use_add): 

"""A factory for ``threaded`` decorators. """ 

from sympy.core import sympify 

from sympy.matrices import MatrixBase 

 

@wraps(func) 

def threaded_func(expr, *args, **kwargs): 

if isinstance(expr, MatrixBase): 

return expr.applyfunc(lambda f: func(f, *args, **kwargs)) 

elif iterable(expr): 

try: 

return expr.__class__([func(f, *args, **kwargs) for f in expr]) 

except TypeError: 

return expr 

else: 

expr = sympify(expr) 

 

if use_add and expr.is_Add: 

return expr.__class__(*[ func(f, *args, **kwargs) for f in expr.args ]) 

elif expr.is_Relational: 

return expr.__class__(func(expr.lhs, *args, **kwargs), 

func(expr.rhs, *args, **kwargs)) 

else: 

return func(expr, *args, **kwargs) 

 

return threaded_func 

 

 

def threaded(func): 

"""Apply ``func`` to sub--elements of an object, including :class:`Add`. 

 

This decorator is intended to make it uniformly possible to apply a 

function to all elements of composite objects, e.g. matrices, lists, tuples 

and other iterable containers, or just expressions. 

 

This version of :func:`threaded` decorator allows threading over 

elements of :class:`Add` class. If this behavior is not desirable 

use :func:`xthreaded` decorator. 

 

Functions using this decorator must have the following signature:: 

 

@threaded 

def function(expr, *args, **kwargs): 

 

""" 

return threaded_factory(func, True) 

 

 

def xthreaded(func): 

"""Apply ``func`` to sub--elements of an object, excluding :class:`Add`. 

 

This decorator is intended to make it uniformly possible to apply a 

function to all elements of composite objects, e.g. matrices, lists, tuples 

and other iterable containers, or just expressions. 

 

This version of :func:`threaded` decorator disallows threading over 

elements of :class:`Add` class. If this behavior is not desirable 

use :func:`threaded` decorator. 

 

Functions using this decorator must have the following signature:: 

 

@xthreaded 

def function(expr, *args, **kwargs): 

 

""" 

return threaded_factory(func, False) 

 

 

def conserve_mpmath_dps(func): 

"""After the function finishes, resets the value of mpmath.mp.dps to 

the value it had before the function was run.""" 

import functools 

import mpmath 

 

def func_wrapper(): 

dps = mpmath.mp.dps 

try: 

func() 

finally: 

mpmath.mp.dps = dps 

 

func_wrapper = functools.update_wrapper(func_wrapper, func) 

return func_wrapper 

 

 

class no_attrs_in_subclass(object): 

"""Don't 'inherit' certain attributes from a base class 

 

>>> from sympy.utilities.decorator import no_attrs_in_subclass 

 

>>> class A(object): 

... x = 'test' 

 

>>> A.x = no_attrs_in_subclass(A, A.x) 

 

>>> class B(A): 

... pass 

 

>>> hasattr(A, 'x') 

True 

>>> hasattr(B, 'x') 

False 

 

""" 

def __init__(self, cls, f): 

self.cls = cls 

self.f = f 

 

def __get__(self, instance, owner=None): 

if owner == self.cls: 

if hasattr(self.f, '__get__'): 

return self.f.__get__(instance, owner) 

return self.f 

raise AttributeError 

 

 

def doctest_depends_on(exe=None, modules=None, disable_viewers=None): 

"""Adds metadata about the depenencies which need to be met for doctesting 

the docstrings of the decorated objects.""" 

pyglet = False 

if modules is not None and 'pyglet' in modules: 

pyglet = True 

 

def depends_on_deco(fn): 

fn._doctest_depends_on = dict(exe=exe, modules=modules, 

disable_viewers=disable_viewers, 

pyglet=pyglet) 

 

# once we drop py2.5 support and use class decorators this evaluates 

# to True 

if inspect.isclass(fn): 

fn._doctest_depdends_on = no_attrs_in_subclass(fn, fn._doctest_depends_on) 

return fn 

return depends_on_deco 

 

def public(obj): 

""" 

Append ``obj``'s name to global ``__all__`` variable (call site). 

 

By using this decorator on functions or classes you achieve the same goal 

as by filling ``__all__`` variables manually, you just don't have to repeat 

yourself (object's name). You also know if object is public at definition 

site, not at some random location (where ``__all__`` was set). 

 

Note that in multiple decorator setup (in almost all cases) ``@public`` 

decorator must be applied before any other decorators, because it relies 

on the pointer to object's global namespace. If you apply other decorators 

first, ``@public`` may end up modifying the wrong namespace. 

 

Examples 

======== 

 

>>> from sympy.utilities.decorator import public 

 

>>> __all__ 

Traceback (most recent call last): 

... 

NameError: name '__all__' is not defined 

 

>>> @public 

... def some_function(): 

... pass 

 

>>> __all__ 

['some_function'] 

 

""" 

if isinstance(obj, types.FunctionType): 

ns = get_function_globals(obj) 

name = get_function_name(obj) 

elif isinstance(obj, (type(type), class_types)): 

ns = sys.modules[obj.__module__].__dict__ 

name = obj.__name__ 

else: 

raise TypeError("expected a function or a class, got %s" % obj) 

 

if "__all__" not in ns: 

ns["__all__"] = [name] 

else: 

ns["__all__"].append(name) 

 

return obj 

 

 

def memoize_property(storage): 

"""Create a property, where the lookup is stored in ``storage``""" 

def decorator(method): 

name = method.__name__ 

def wrapper(self): 

if name not in storage: 

storage[name] = method(self) 

return storage[name] 

return property(update_wrapper(wrapper, method)) 

return decorator