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

1from __future__ import absolute_import 

2 

3from . import core 

4import itertools 

5import copy 

6import six 

7 

8 

9class ParameterError(core.WidgetError): 

10 "Errors related to parameters." 

11 

12 

13class _Required(object): 

14 """This class is used to mark a widget parameter as being required, by 

15 setting the default value to this.""" 

16 def __repr__(self): 

17 return 'Required' 

18Required = _Required() 

19 

20 

21class _Auto(object): 

22 """ 

23 Used to explicitly mark a parameter as being automatically generated. 

24 """ 

25 def __repr__(self): 

26 return 'Auto' 

27Auto = _Auto() 

28 

29 

30class Deferred(object): 

31 """This class is used as a wrapper around a parameter value. It takes a 

32 callable, which will be called every time the widget is displayed, with 

33 the returned value giving the parameter value.""" 

34 

35 def __init__(self, fn): 

36 self.fn = fn 

37 

38 def __repr__(self): 

39 doc = self.fn.__doc__ if self.fn.__doc__ else '<Deferred>' 

40 return '<Deferred: %s>' % doc 

41 

42 

43class _Default(object): 

44 def __repr__(self): 

45 return 'Default' 

46Default = _Default() 

47 

48_param_seq = itertools.count(0) 

49 

50 

51class Param(object): 

52 """A parameter for a widget. 

53 

54 `description` 

55 A string to describe the parameter. When overriding a parameter 

56 description, the string can include ``$$`` to insert the previous 

57 description. 

58 

59 `default` 

60 The default value for the parameter. If no defalt is specified, 

61 the parameter is a required parameter. This can also be specified 

62 explicitly using tw.Required. 

63 

64 `request_local` 

65 Can the parameter be overriden on a per-request basis? (default: 

66 True) 

67 

68 `attribute` 

69 Should the parameter be automatically included as an attribute? 

70 (default: False) 

71 

72 `view_name` 

73 The name used for the attribute. This is useful for attributes like 

74 *class* which are reserved names in Python. If this is None, the name 

75 is used. (default: None) 

76 

77 The class takes care to record which arguments have been explictly 

78 specifed, even if to their default value. If a parameter from a base 

79 class is updated in a subclass, arguments that have been explicitly 

80 specified will override the base class. 

81 """ 

82 

83 child_param = False 

84 internal = False 

85 name = None 

86 defined_on = None 

87 view_name = None 

88 

89 def __init__(self, description=Default, default=Default, 

90 request_local=Default, attribute=Default, 

91 view_name=Default): 

92 self._seq = six.advance_iterator(_param_seq) 

93 

94 self.description = None 

95 if description is not Default: 

96 self.description = description 

97 self.default = Required 

98 if default is not Default: 

99 self.default = default 

100 self.request_local = True 

101 if request_local is not Default: 

102 self.request_local = request_local 

103 self.attribute = False 

104 if attribute is not Default: 

105 self.attribute = attribute 

106 self.view_name = None 

107 if view_name is not Default: 

108 self.view_name = view_name 

109 

110 self.specified = [] 

111 args = [ 

112 'description', 

113 'default', 

114 'request_local', 

115 'attribute', 

116 'view_name', 

117 ] 

118 for arg in args: 

119 if locals()[arg] is not Default: 

120 self.specified.append(arg) 

121 

122 def __repr__(self): 

123 return '%s: %s (default: %s, defined on: %s)' % ( 

124 self.name, self.description, self.default, self.defined_on) 

125 

126 

127class Variable(Param): 

128 """A variable - a parameter that is passed from the widget to the template, 

129 but cannot be controlled by the user. These do not appear in the concise 

130 documentation for the widget. 

131 """ 

132 internal = True 

133 

134 def __init__(self, description=Default, **kw): 

135 kw.setdefault('default', None) 

136 super(Variable, self).__init__(description, **kw) 

137 self.specified.append('internal') 

138 

139 

140class ChildParam(Param): 

141 """A parameter that applies to children of this widget 

142 

143 This is useful for situations such as a layout widget, which adds a 

144 :attr:`label` parameter to each of its children. When a Widget subclass is 

145 defined with a parent, the widget picks up the defaults for any child 

146 parameters from the parent. 

147 """ 

148 child_param = True 

149 

150 

151class ChildVariable(Variable, ChildParam): 

152 """A variable that applies to children of this widget 

153 """ 

154 pass 

155 

156 

157class ParamMeta(type): 

158 "Meta class the collects parameters." 

159 

160 def __new__(meta, name, bases, dct): 

161 """Create a new `Widget` subclass. This detects `Param` instances 

162 defined declaratively, updates with information from the containing 

163 class, and stores the objects in `_params`.""" 

164 

165 params = {} 

166 for b in bases: 

167 if hasattr(b, '_params'): 

168 params.update(b._all_params) 

169 

170 for pname, prm in list(dct.items()): 

171 if isinstance(prm, Param): 

172 if pname in params: 

173 newprm = prm 

174 prm = copy.copy(params[pname]) 

175 for a in newprm.specified: 

176 setattr(prm, a, getattr(newprm, a)) 

177 else: 

178 prm.name = pname 

179 if prm.view_name is None: 

180 prm.view_name = pname 

181 prm.defined_on = name 

182 

183 params[pname] = prm 

184 if not prm.child_param and prm.default is not Required: 

185 dct[pname] = prm.default 

186 else: 

187 del dct[pname] 

188 elif pname in params: 

189 params[pname] = copy.copy(params[pname]) 

190 params[pname].default = prm 

191 if prm is Required and pname != 'validator': 

192 del dct[pname] 

193 

194 ins = type.__new__(meta, name, bases, dct) 

195 ins._all_params = params 

196 ins._params = dict((p.name, p) for p in params.values() 

197 if not p.child_param) 

198 return ins 

199 

200 

201class Parametered(six.with_metaclass(ParamMeta, object)): 

202 pass