diff --git a/docs/releases/upcoming/1684.bugfix.rst b/docs/releases/upcoming/1684.bugfix.rst new file mode 100644 index 000000000..85b229836 --- /dev/null +++ b/docs/releases/upcoming/1684.bugfix.rst @@ -0,0 +1,2 @@ +Add RangeEditor support for format_func and deprecate ``format`` trait on +RangeEditor factory / toolkit specific Editor implementations (#1684) \ No newline at end of file diff --git a/traitsui/editors/range_editor.py b/traitsui/editors/range_editor.py index 42a21cbd8..4cc03d81b 100644 --- a/traitsui/editors/range_editor.py +++ b/traitsui/editors/range_editor.py @@ -10,6 +10,7 @@ """ Defines the range editor factory for all traits user interface toolkits. """ +import warnings from types import CodeType @@ -65,7 +66,12 @@ class RangeEditor(EditorFactory): high_name = Str() #: Formatting string used to format value and labels - format = Str("%s") + format_str = Str("%s") + + #: Deprecated: Please use ``format_str`` instead. + #: See enthought/traitsui#1704 + #: Formatting string used to format value and labels. + format = Property(Str, observe='format_str') #: Is the range for floating pointer numbers (vs. integers)? is_float = Bool(Undefined) @@ -194,6 +200,23 @@ def _get_low_high(self, ui): # ------------------------------------------------------------------------- # Property getters. # ------------------------------------------------------------------------- + + def _get_format(self): + warnings.warn( + "Use of format trait is deprecated. Use format_str instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.format_str + + def _set_format(self, format_string): + warnings.warn( + "Use of format trait is deprecated. Use format_str instead.", + DeprecationWarning, + stacklevel=2, + ) + self.format_str = format_string + def _get_simple_editor_class(self): """ Returns the editor class to use for a simple style. diff --git a/traitsui/qt4/range_editor.py b/traitsui/qt4/range_editor.py index 37741ae2b..9904aff71 100644 --- a/traitsui/qt4/range_editor.py +++ b/traitsui/qt4/range_editor.py @@ -80,7 +80,7 @@ class SimpleSliderEditor(BaseRangeEditor): #: High value for the slider range high = Any() - #: Formatting string used to format value and labels + #: Deprecated: This trait is no longer used. See enthought/traitsui#1704 format = Str() def init(self, parent): @@ -94,8 +94,6 @@ def init(self, parent): if not factory.high_name: self.high = factory.high - self.format = factory.format - self.evaluate = factory.evaluate self.sync_value(factory.evaluate_name, "evaluate", "from") @@ -111,7 +109,7 @@ def init(self, parent): try: if not (self.low <= fvalue <= self.high): fvalue = self.low - fvalue_text = self.format % fvalue + fvalue_text = self.string_value(fvalue) except: fvalue_text = "" fvalue = self.low @@ -153,11 +151,11 @@ def init(self, parent): low_label = factory.low_label if factory.low_name != "": - low_label = self.format % self.low + low_label = self.string_value(self.low) high_label = factory.high_label if factory.high_name != "": - high_label = self.format % self.high + high_label = self.string_value(self.high) self._label_lo.setText(low_label) self._label_hi.setText(high_label) @@ -171,7 +169,7 @@ def update_object_on_scroll(self, pos): """ Handles the user changing the current slider value. """ value = self._convert_from_slider(pos) - self.control.text.setText(self.format % value) + self.control.text.setText(self.string_value(value)) try: self.value = value except Exception as exc: @@ -221,7 +219,7 @@ def update_editor(self): low = self.low high = self.high try: - text = self.format % value + text = self.string_value(value) 1 / (low <= value <= high) except: text = "" @@ -250,7 +248,7 @@ def _low_changed(self, low): self.value = int(low) if self._label_lo is not None: - self._label_lo.setText(self.format % low) + self._label_lo.setText(self.string_value(low)) self.update_editor() def _high_changed(self, high): @@ -261,7 +259,7 @@ def _high_changed(self, high): self.value = int(high) if self._label_hi is not None: - self._label_hi.setText(self.format % high) + self._label_hi.setText(self.string_value(high)) self.update_editor() def _convert_to_slider(self, value): diff --git a/traitsui/tests/editors/test_range_editor.py b/traitsui/tests/editors/test_range_editor.py index a12c5f7b3..6e131e24e 100644 --- a/traitsui/tests/editors/test_range_editor.py +++ b/traitsui/tests/editors/test_range_editor.py @@ -320,3 +320,77 @@ def test_modify_slider_log_range_slider(self): displayed = text.inspect(DisplayedText()) self.assertEqual(model.float_value, 10.0) self.assertEqual(displayed, str(model.float_value)) + + def test_format_func(self): + + def num_to_time(num): + minutes = int(num / 60) + if minutes < 10: + minutes_str = '0' + str(minutes) + else: + minutes_str = str(minutes) + seconds = num % 60 + if seconds < 10: + seconds_str = '0' + str(seconds) + else: + seconds_str = str(seconds) + return minutes_str + ':' + seconds_str + + model = RangeModel() + view = View( + Item( + "float_value", + editor=RangeEditor(format_func=num_to_time) + ) + ) + tester = UITester() + with tester.create_ui(model, dict(view=view)) as ui: + float_value_field = tester.find_by_name(ui, "float_value") + float_value_text = float_value_field.locate(Textbox()) + self.assertEqual( + float_value_text.inspect(DisplayedText()), "00:00.1" + ) + + def test_editor_factory_format(self): + """ + format trait on RangeEditor editor factory has been deprecated in + favor of format_str. However, behavior should be unchanged. + """ + model = RangeModel() + with self.assertWarns(DeprecationWarning): + view = View( + Item( + "float_value", + editor=RangeEditor(format="%s ...") + ) + ) + tester = UITester() + with tester.create_ui(model, dict(view=view)) as ui: + float_value_field = tester.find_by_name(ui, "float_value") + float_value_text = float_value_field.locate(Textbox()) + self.assertEqual( + float_value_text.inspect(DisplayedText()), "0.1 ..." + ) + + def test_editor_format(self): + """ + The format trait on an Editor instance previously potentially + could override the factory. Now that is not the case. + """ + model = RangeModel() + with self.assertWarns(DeprecationWarning): + view = View( + Item( + "float_value", + editor=RangeEditor(format="%s ...") + ) + ) + tester = UITester() + with tester.create_ui(model, dict(view=view)) as ui: + float_value_field = tester.find_by_name(ui, "float_value") + float_value_field._target.format = "%s +++" + model.float_value = 0.2 + float_value_text = float_value_field.locate(Textbox()) + self.assertEqual( + float_value_text.inspect(DisplayedText()), "0.2 ..." + ) diff --git a/traitsui/wx/range_editor.py b/traitsui/wx/range_editor.py index 8bcccef75..d09966bd9 100644 --- a/traitsui/wx/range_editor.py +++ b/traitsui/wx/range_editor.py @@ -74,7 +74,7 @@ class SimpleSliderEditor(BaseRangeEditor): #: High value for the slider range high = Any() - #: Formatting string used to format value and labels + #: Deprecated: This trait is no longer used. See enthought/traitsui#1704 format = Str() #: Flag indicating that the UI is in the process of being updated @@ -91,8 +91,6 @@ def init(self, parent): if not factory.high_name: self.high = factory.high - self.format = factory.format - self.evaluate = factory.evaluate self.sync_value(factory.evaluate_name, "evaluate", "from") @@ -111,7 +109,7 @@ def init(self, parent): fvalue = self.low else: try: - fvalue_text = self.format % fvalue + fvalue_text = self.string_value(fvalue) except (ValueError, TypeError) as e: fvalue_text = "" @@ -157,11 +155,11 @@ def init(self, parent): low_label = factory.low_label if factory.low_name != "": - low_label = self.format % self.low + low_label = self.string_value(self.low) high_label = factory.high_label if factory.high_name != "": - high_label = self.format % self.high + high_label = self.string_value(self.high) self._label_lo.SetLabel(low_label) self._label_hi.SetLabel(high_label) @@ -191,7 +189,7 @@ def update_object_on_scroll(self, event): ): try: self.ui_changing = True - self.control.text.SetValue(self.format % value) + self.control.text.SetValue(self.string_value(value)) self.value = value except TraitError: pass @@ -253,7 +251,7 @@ def update_editor(self): """ value = self.value try: - text = self.format % value + text = self.string_value(value) 1 // (self.low <= value <= self.high) except: text = "" @@ -296,7 +294,7 @@ def _low_changed(self, low): self.value = int(low) if self._label_lo is not None: - self._label_lo.SetLabel(self.format % low) + self._label_lo.SetLabel(self.string_value(low)) self.update_editor() def _high_changed(self, high): @@ -307,7 +305,7 @@ def _high_changed(self, high): self.value = int(high) if self._label_hi is not None: - self._label_hi.SetLabel(self.format % high) + self._label_hi.SetLabel(self.string_value(high)) self.update_editor()