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

from __future__ import absolute_import 

 

from . import core 

import itertools 

import copy 

import six 

 

 

class ParameterError(core.WidgetError): 

    "Errors related to parameters." 

 

 

class _Required(object): 

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

    setting the default value to this.""" 

    def __repr__(self): 

        return 'Required' 

Required = _Required() 

 

 

class _Auto(object): 

    """ 

    Used to explicitly mark a parameter as being automatically generated. 

    """ 

    def __repr__(self): 

        return 'Auto' 

Auto = _Auto() 

 

 

class Deferred(object): 

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

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

    the returned value giving the parameter value.""" 

 

    def __init__(self, fn): 

        self.fn = fn 

 

    def __repr__(self): 

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

        return '<Deferred: %s>' % doc 

 

 

class _Default(object): 

    def __repr__(self): 

        return 'Default' 

Default = _Default() 

 

_param_seq = itertools.count(0) 

 

 

class Param(object): 

    """A parameter for a widget. 

 

    `description` 

        A string to describe the parameter. When overriding a parameter 

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

        description. 

 

    `default` 

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

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

        explicitly using tw.Required. 

 

    `request_local` 

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

        True) 

 

    `attribute` 

        Should the parameter be automatically included as an attribute? 

        (default: False) 

 

    `view_name` 

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

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

        is used. (default: None) 

 

    The class takes care to record which arguments have been explictly 

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

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

    specified will override the base class. 

    """ 

 

    child_param = False 

    internal = False 

    name = None 

    defined_on = None 

    view_name = None 

 

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

                 request_local=Default, attribute=Default, 

                 view_name=Default): 

        self._seq = six.advance_iterator(_param_seq) 

 

        self.description = None 

        if description is not Default: 

            self.description = description 

        self.default = Required 

        if default is not Default: 

            self.default = default 

        self.request_local = True 

        if request_local is not Default: 

            self.request_local = request_local 

        self.attribute = False 

        if attribute is not Default: 

            self.attribute = attribute 

        self.view_name = None 

        if view_name is not Default: 

            self.view_name = view_name 

 

        self.specified = [] 

        args = [ 

            'description', 

            'default', 

            'request_local', 

            'attribute', 

            'view_name', 

        ] 

        for arg in args: 

            if locals()[arg] is not Default: 

                self.specified.append(arg) 

 

    def __repr__(self): 

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

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

 

 

class Variable(Param): 

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

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

    documentation for the widget. 

    """ 

    internal = True 

 

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

        kw.setdefault('default', None) 

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

        self.specified.append('internal') 

 

 

class ChildParam(Param): 

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

 

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

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

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

    parameters from the parent. 

    """ 

    child_param = True 

 

 

class ChildVariable(Variable, ChildParam): 

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

    """ 

    pass 

 

 

class ParamMeta(type): 

    "Meta class the collects parameters." 

 

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

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

        defined declaratively, updates with information from the containing 

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

 

        params = {} 

        for b in bases: 

            if hasattr(b, '_params'): 

                params.update(b._all_params) 

 

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

            if isinstance(prm, Param): 

                if pname in params: 

                    newprm = prm 

                    prm = copy.copy(params[pname]) 

                    for a in newprm.specified: 

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

                else: 

                    prm.name = pname 

                    if prm.view_name is None: 

                        prm.view_name = pname 

                    prm.defined_on = name 

 

                params[pname] = prm 

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

                    dct[pname] = prm.default 

                else: 

                    del dct[pname] 

            elif pname in params: 

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

                params[pname].default = prm 

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

                    del dct[pname] 

 

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

        ins._all_params = params 

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

                                                    if not p.child_param) 

        return ins 

 

 

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

    pass