##// END OF EJS Templates
Validation on the python side
Jonathan Frederic -
Show More
@@ -1,280 +1,295 b''
1 1 """Float class.
2 2
3 3 Represents an unbounded float using a widget.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from .widget import DOMWidget, register
17 17 from IPython.utils.traitlets import Unicode, CFloat, Bool, CaselessStrEnum, Tuple
18 18 from IPython.utils.warn import DeprecatedClass
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Classes
22 22 #-----------------------------------------------------------------------------
23 23 class _Float(DOMWidget):
24 24 value = CFloat(0.0, help="Float value", sync=True)
25 25 disabled = Bool(False, help="Enable or disable user changes", sync=True)
26 26 description = Unicode(help="Description of the value this widget represents", sync=True)
27 27
28 28 def __init__(self, value=None, **kwargs):
29 29 if value is not None:
30 30 kwargs['value'] = value
31 31 super(_Float, self).__init__(**kwargs)
32 32
33 33 class _BoundedFloat(_Float):
34 34 max = CFloat(100.0, help="Max value", sync=True)
35 35 min = CFloat(0.0, help="Min value", sync=True)
36 36 step = CFloat(0.1, help="Minimum step that the value can take (ignored by some views)", sync=True)
37 37
38 38 def __init__(self, *pargs, **kwargs):
39 39 """Constructor"""
40 40 super(_BoundedFloat, self).__init__(*pargs, **kwargs)
41 self._validate('value', None, self.value)
42 self.on_trait_change(self._validate, ['value', 'min', 'max'])
41 self._value_changed('value', None, self.value)
42 self._min_changed('min', None, self.min)
43 self._max_changed('max', None, self.max)
43 44
44 def _validate(self, name, old, new):
45 """Validate value, max, min."""
45 def _value_changed(self, name, old, new):
46 """Validate value."""
46 47 if self.min > new or new > self.max:
47 48 self.value = min(max(new, self.min), self.max)
48 49
50 def _max_changed(self, name, old, new):
51 """Make sure the min is always <= the max."""
52 if new < self.min:
53 raise ValueError("setting max < min")
54 if new < self.value:
55 self.value = new
56
57 def _min_changed(self, name, old, new):
58 """Make sure the max is always >= the min."""
59 if new > self.max:
60 raise ValueError("setting min > max")
61 if new > self.value:
62 self.value = new
63
49 64
50 65 @register('IPython.FloatText')
51 66 class FloatText(_Float):
52 67 """ Displays a float value within a textbox. For a textbox in
53 68 which the value must be within a specific range, use BoundedFloatText.
54 69
55 70 Parameters
56 71 ----------
57 72 value : float
58 73 value displayed
59 74 description : str
60 75 description displayed next to the textbox
61 76 color : str Unicode color code (eg. '#C13535'), optional
62 77 color of the value displayed
63 78 """
64 79 _view_name = Unicode('FloatTextView', sync=True)
65 80
66 81
67 82 @register('IPython.BoundedFloatText')
68 83 class BoundedFloatText(_BoundedFloat):
69 84 """ Displays a float value within a textbox. Value must be within the range specified.
70 85 For a textbox in which the value doesn't need to be within a specific range, use FloatText.
71 86
72 87 Parameters
73 88 ----------
74 89 value : float
75 90 value displayed
76 91 min : float
77 92 minimal value of the range of possible values displayed
78 93 max : float
79 94 maximal value of the range of possible values displayed
80 95 description : str
81 96 description displayed next to the textbox
82 97 color : str Unicode color code (eg. '#C13535'), optional
83 98 color of the value displayed
84 99 """
85 100 _view_name = Unicode('FloatTextView', sync=True)
86 101
87 102
88 103 @register('IPython.FloatSlider')
89 104 class FloatSlider(_BoundedFloat):
90 105 """ Slider/trackbar of floating values with the specified range.
91 106
92 107 Parameters
93 108 ----------
94 109 value : float
95 110 position of the slider
96 111 min : float
97 112 minimal position of the slider
98 113 max : float
99 114 maximal position of the slider
100 115 step : float
101 116 step of the trackbar
102 117 description : str
103 118 name of the slider
104 119 orientation : {'vertical', 'horizontal}, optional
105 120 default is horizontal
106 121 readout : {True, False}, optional
107 122 default is True, display the current value of the slider next to it
108 123 slider_color : str Unicode color code (eg. '#C13535'), optional
109 124 color of the slider
110 125 color : str Unicode color code (eg. '#C13535'), optional
111 126 color of the value displayed (if readout == True)
112 127 """
113 128 _view_name = Unicode('FloatSliderView', sync=True)
114 129 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
115 130 default_value='horizontal',
116 131 help="Vertical or horizontal.", allow_none=False, sync=True)
117 132 _range = Bool(False, help="Display a range selector", sync=True)
118 133 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
119 134 slider_color = Unicode(sync=True)
120 135
121 136
122 137 @register('IPython.FloatProgress')
123 138 class FloatProgress(_BoundedFloat):
124 139 """ Displays a progress bar.
125 140
126 141 Parameters
127 142 -----------
128 143 value : float
129 144 position within the range of the progress bar
130 145 min : float
131 146 minimal position of the slider
132 147 max : float
133 148 maximal position of the slider
134 149 step : float
135 150 step of the progress bar
136 151 description : str
137 152 name of the progress bar
138 153 bar_style: {'success', 'info', 'warning', 'danger', ''}, optional
139 154 color of the progress bar, default is '' (blue)
140 155 colors are: 'success'-green, 'info'-light blue, 'warning'-orange, 'danger'-red
141 156 """
142 157 _view_name = Unicode('ProgressView', sync=True)
143 158
144 159 bar_style = CaselessStrEnum(
145 160 values=['success', 'info', 'warning', 'danger', ''],
146 161 default_value='', allow_none=True, sync=True, help="""Use a
147 162 predefined styling for the progess bar.""")
148 163
149 164 class _FloatRange(_Float):
150 165 value = Tuple(CFloat, CFloat, default_value=(0.0, 1.0), help="Tuple of (lower, upper) bounds", sync=True)
151 166 lower = CFloat(0.0, help="Lower bound", sync=False)
152 167 upper = CFloat(1.0, help="Upper bound", sync=False)
153 168
154 169 def __init__(self, *pargs, **kwargs):
155 170 value_given = 'value' in kwargs
156 171 lower_given = 'lower' in kwargs
157 172 upper_given = 'upper' in kwargs
158 173 if value_given and (lower_given or upper_given):
159 174 raise ValueError("Cannot specify both 'value' and 'lower'/'upper' for range widget")
160 175 if lower_given != upper_given:
161 176 raise ValueError("Must specify both 'lower' and 'upper' for range widget")
162 177
163 178 DOMWidget.__init__(self, *pargs, **kwargs)
164 179
165 180 # ensure the traits match, preferring whichever (if any) was given in kwargs
166 181 if value_given:
167 182 self.lower, self.upper = self.value
168 183 else:
169 184 self.value = (self.lower, self.upper)
170 185
171 186 self.on_trait_change(self._validate, ['value', 'upper', 'lower'])
172 187
173 188 def _validate(self, name, old, new):
174 189 if name == 'value':
175 190 self.lower, self.upper = min(new), max(new)
176 191 elif name == 'lower':
177 192 self.value = (new, self.value[1])
178 193 elif name == 'upper':
179 194 self.value = (self.value[0], new)
180 195
181 196 class _BoundedFloatRange(_FloatRange):
182 197 step = CFloat(1.0, help="Minimum step that the value can take (ignored by some views)", sync=True)
183 198 max = CFloat(100.0, help="Max value", sync=True)
184 199 min = CFloat(0.0, help="Min value", sync=True)
185 200
186 201 def __init__(self, *pargs, **kwargs):
187 202 any_value_given = 'value' in kwargs or 'upper' in kwargs or 'lower' in kwargs
188 203 _FloatRange.__init__(self, *pargs, **kwargs)
189 204
190 205 # ensure a minimal amount of sanity
191 206 if self.min > self.max:
192 207 raise ValueError("min must be <= max")
193 208
194 209 if any_value_given:
195 210 # if a value was given, clamp it within (min, max)
196 211 self._validate("value", None, self.value)
197 212 else:
198 213 # otherwise, set it to 25-75% to avoid the handles overlapping
199 214 self.value = (0.75*self.min + 0.25*self.max,
200 215 0.25*self.min + 0.75*self.max)
201 216 # callback already set for 'value', 'lower', 'upper'
202 217 self.on_trait_change(self._validate, ['min', 'max'])
203 218
204 219
205 220 def _validate(self, name, old, new):
206 221 if name == "min":
207 222 if new > self.max:
208 223 raise ValueError("setting min > max")
209 224 self.min = new
210 225 elif name == "max":
211 226 if new < self.min:
212 227 raise ValueError("setting max < min")
213 228 self.max = new
214 229
215 230 low, high = self.value
216 231 if name == "value":
217 232 low, high = min(new), max(new)
218 233 elif name == "upper":
219 234 if new < self.lower:
220 235 raise ValueError("setting upper < lower")
221 236 high = new
222 237 elif name == "lower":
223 238 if new > self.upper:
224 239 raise ValueError("setting lower > upper")
225 240 low = new
226 241
227 242 low = max(self.min, min(low, self.max))
228 243 high = min(self.max, max(high, self.min))
229 244
230 245 # determine the order in which we should update the
231 246 # lower, upper traits to avoid a temporary inverted overlap
232 247 lower_first = high < self.lower
233 248
234 249 self.value = (low, high)
235 250 if lower_first:
236 251 self.lower = low
237 252 self.upper = high
238 253 else:
239 254 self.upper = high
240 255 self.lower = low
241 256
242 257
243 258 @register('IPython.FloatRangeSlider')
244 259 class FloatRangeSlider(_BoundedFloatRange):
245 260 """ Slider/trackbar for displaying a floating value range (within the specified range of values).
246 261
247 262 Parameters
248 263 ----------
249 264 value : float tuple
250 265 range of the slider displayed
251 266 min : float
252 267 minimal position of the slider
253 268 max : float
254 269 maximal position of the slider
255 270 step : float
256 271 step of the trackbar
257 272 description : str
258 273 name of the slider
259 274 orientation : {'vertical', 'horizontal}, optional
260 275 default is horizontal
261 276 readout : {True, False}, optional
262 277 default is True, display the current value of the slider next to it
263 278 slider_color : str Unicode color code (eg. '#C13535'), optional
264 279 color of the slider
265 280 color : str Unicode color code (eg. '#C13535'), optional
266 281 color of the value displayed (if readout == True)
267 282 """
268 283 _view_name = Unicode('FloatSliderView', sync=True)
269 284 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
270 285 default_value='horizontal', allow_none=False,
271 286 help="Vertical or horizontal.", sync=True)
272 287 _range = Bool(True, help="Display a range selector", sync=True)
273 288 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
274 289 slider_color = Unicode(sync=True)
275 290
276 291 # Remove in IPython 4.0
277 292 FloatTextWidget = DeprecatedClass(FloatText, 'FloatTextWidget')
278 293 BoundedFloatTextWidget = DeprecatedClass(BoundedFloatText, 'BoundedFloatTextWidget')
279 294 FloatSliderWidget = DeprecatedClass(FloatSlider, 'FloatSliderWidget')
280 295 FloatProgressWidget = DeprecatedClass(FloatProgress, 'FloatProgressWidget')
@@ -1,202 +1,206 b''
1 1 """Int class.
2 2
3 3 Represents an unbounded int using a widget.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (c) 2013, the IPython Development Team.
7 7 #
8 8 # Distributed under the terms of the Modified BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from .widget import DOMWidget, register
17 17 from IPython.utils.traitlets import Unicode, CInt, Bool, CaselessStrEnum, Tuple
18 18 from IPython.utils.warn import DeprecatedClass
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Classes
22 22 #-----------------------------------------------------------------------------
23 23 class _Int(DOMWidget):
24 24 """Base class used to create widgets that represent an int."""
25 25 value = CInt(0, help="Int value", sync=True)
26 26 disabled = Bool(False, help="Enable or disable user changes", sync=True)
27 27 description = Unicode(help="Description of the value this widget represents", sync=True)
28 28
29 29 def __init__(self, value=None, **kwargs):
30 30 if value is not None:
31 31 kwargs['value'] = value
32 32 super(_Int, self).__init__(**kwargs)
33 33
34 34 class _BoundedInt(_Int):
35 35 """Base class used to create widgets that represent a int that is bounded
36 36 by a minium and maximum."""
37 37 step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
38 38 max = CInt(100, help="Max value", sync=True)
39 39 min = CInt(0, help="Min value", sync=True)
40 40
41 41 def __init__(self, *pargs, **kwargs):
42 42 """Constructor"""
43 43 super(_BoundedInt, self).__init__(*pargs, **kwargs)
44 self.on_trait_change(self._validate_value, ['value'])
45 self.on_trait_change(self._handle_max_changed, ['max'])
46 self.on_trait_change(self._handle_min_changed, ['min'])
44 self._value_changed('value', None, self.value)
45 self._min_changed('min', None, self.min)
46 self._max_changed('max', None, self.max)
47 47
48 def _validate_value(self, name, old, new):
48 def _value_changed(self, name, old, new):
49 49 """Validate value."""
50 50 if self.min > new or new > self.max:
51 51 self.value = min(max(new, self.min), self.max)
52 52
53 def _handle_max_changed(self, name, old, new):
53 def _max_changed(self, name, old, new):
54 54 """Make sure the min is always <= the max."""
55 55 if new < self.min:
56 56 raise ValueError("setting max < min")
57 if new < self.value:
58 self.value = new
57 59
58 def _handle_min_changed(self, name, old, new):
60 def _min_changed(self, name, old, new):
59 61 """Make sure the max is always >= the min."""
60 62 if new > self.max:
61 63 raise ValueError("setting min > max")
64 if new > self.value:
65 self.value = new
62 66
63 67 @register('IPython.IntText')
64 68 class IntText(_Int):
65 69 """Textbox widget that represents a int."""
66 70 _view_name = Unicode('IntTextView', sync=True)
67 71
68 72
69 73 @register('IPython.BoundedIntText')
70 74 class BoundedIntText(_BoundedInt):
71 75 """Textbox widget that represents a int bounded by a minimum and maximum value."""
72 76 _view_name = Unicode('IntTextView', sync=True)
73 77
74 78
75 79 @register('IPython.IntSlider')
76 80 class IntSlider(_BoundedInt):
77 81 """Slider widget that represents a int bounded by a minimum and maximum value."""
78 82 _view_name = Unicode('IntSliderView', sync=True)
79 83 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
80 84 default_value='horizontal', allow_none=False,
81 85 help="Vertical or horizontal.", sync=True)
82 86 _range = Bool(False, help="Display a range selector", sync=True)
83 87 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
84 88 slider_color = Unicode(sync=True)
85 89
86 90
87 91 @register('IPython.IntProgress')
88 92 class IntProgress(_BoundedInt):
89 93 """Progress bar that represents a int bounded by a minimum and maximum value."""
90 94 _view_name = Unicode('ProgressView', sync=True)
91 95
92 96 bar_style = CaselessStrEnum(
93 97 values=['success', 'info', 'warning', 'danger', ''],
94 98 default_value='', allow_none=True, sync=True, help="""Use a
95 99 predefined styling for the progess bar.""")
96 100
97 101 class _IntRange(_Int):
98 102 value = Tuple(CInt, CInt, default_value=(0, 1), help="Tuple of (lower, upper) bounds", sync=True)
99 103 lower = CInt(0, help="Lower bound", sync=False)
100 104 upper = CInt(1, help="Upper bound", sync=False)
101 105
102 106 def __init__(self, *pargs, **kwargs):
103 107 value_given = 'value' in kwargs
104 108 lower_given = 'lower' in kwargs
105 109 upper_given = 'upper' in kwargs
106 110 if value_given and (lower_given or upper_given):
107 111 raise ValueError("Cannot specify both 'value' and 'lower'/'upper' for range widget")
108 112 if lower_given != upper_given:
109 113 raise ValueError("Must specify both 'lower' and 'upper' for range widget")
110 114
111 115 super(_IntRange, self).__init__(*pargs, **kwargs)
112 116
113 117 # ensure the traits match, preferring whichever (if any) was given in kwargs
114 118 if value_given:
115 119 self.lower, self.upper = self.value
116 120 else:
117 121 self.value = (self.lower, self.upper)
118 122
119 123 self.on_trait_change(self._validate, ['value', 'upper', 'lower'])
120 124
121 125 def _validate(self, name, old, new):
122 126 if name == 'value':
123 127 self.lower, self.upper = min(new), max(new)
124 128 elif name == 'lower':
125 129 self.value = (new, self.value[1])
126 130 elif name == 'upper':
127 131 self.value = (self.value[0], new)
128 132
129 133 class _BoundedIntRange(_IntRange):
130 134 step = CInt(1, help="Minimum step that the value can take (ignored by some views)", sync=True)
131 135 max = CInt(100, help="Max value", sync=True)
132 136 min = CInt(0, help="Min value", sync=True)
133 137
134 138 def __init__(self, *pargs, **kwargs):
135 139 any_value_given = 'value' in kwargs or 'upper' in kwargs or 'lower' in kwargs
136 140 _IntRange.__init__(self, *pargs, **kwargs)
137 141
138 142 # ensure a minimal amount of sanity
139 143 if self.min > self.max:
140 144 raise ValueError("min must be <= max")
141 145
142 146 if any_value_given:
143 147 # if a value was given, clamp it within (min, max)
144 148 self._validate("value", None, self.value)
145 149 else:
146 150 # otherwise, set it to 25-75% to avoid the handles overlapping
147 151 self.value = (0.75*self.min + 0.25*self.max,
148 152 0.25*self.min + 0.75*self.max)
149 153 # callback already set for 'value', 'lower', 'upper'
150 154 self.on_trait_change(self._validate, ['min', 'max'])
151 155
152 156 def _validate(self, name, old, new):
153 157 if name == "min":
154 158 if new > self.max:
155 159 raise ValueError("setting min > max")
156 160 elif name == "max":
157 161 if new < self.min:
158 162 raise ValueError("setting max < min")
159 163
160 164 low, high = self.value
161 165 if name == "value":
162 166 low, high = min(new), max(new)
163 167 elif name == "upper":
164 168 if new < self.lower:
165 169 raise ValueError("setting upper < lower")
166 170 high = new
167 171 elif name == "lower":
168 172 if new > self.upper:
169 173 raise ValueError("setting lower > upper")
170 174 low = new
171 175
172 176 low = max(self.min, min(low, self.max))
173 177 high = min(self.max, max(high, self.min))
174 178
175 179 # determine the order in which we should update the
176 180 # lower, upper traits to avoid a temporary inverted overlap
177 181 lower_first = high < self.lower
178 182
179 183 self.value = (low, high)
180 184 if lower_first:
181 185 self.lower = low
182 186 self.upper = high
183 187 else:
184 188 self.upper = high
185 189 self.lower = low
186 190
187 191 @register('IPython.IntRangeSlider')
188 192 class IntRangeSlider(_BoundedIntRange):
189 193 """Slider widget that represents a pair of ints between a minimum and maximum value."""
190 194 _view_name = Unicode('IntSliderView', sync=True)
191 195 orientation = CaselessStrEnum(values=['horizontal', 'vertical'],
192 196 default_value='horizontal', allow_none=False,
193 197 help="Vertical or horizontal.", sync=True)
194 198 _range = Bool(True, help="Display a range selector", sync=True)
195 199 readout = Bool(True, help="Display the current value of the slider next to it.", sync=True)
196 200 slider_color = Unicode(sync=True)
197 201
198 202 # Remove in IPython 4.0
199 203 IntTextWidget = DeprecatedClass(IntText, 'IntTextWidget')
200 204 BoundedIntTextWidget = DeprecatedClass(BoundedIntText, 'BoundedIntTextWidget')
201 205 IntSliderWidget = DeprecatedClass(IntSlider, 'IntSliderWidget')
202 206 IntProgressWidget = DeprecatedClass(IntProgress, 'IntProgressWidget')
General Comments 0
You need to be logged in to leave comments. Login now