Skip to content

Commit

Permalink
7.0.1 bugfix backport PR (#800)
Browse files Browse the repository at this point in the history
* Fix the back button in the demo. (#799)

* Fixes for Qt DatetimeEditor (#803)

* Fixes for Qt DatetimeEditor.

* Fix handling of changes to editor bounds.

* Remove commented out code from editor example.

* And remove corresponding imports.

* Missed file with explicit defaults.

* Fixes to min/max and value out of range handling.

* Remove NameError and add default root_dir to tutor.py (#813)

* Remove NameError from tutor.py

* Take current directory as default

* Relax argument number constraint

* Rewrite nose tests to use unittest (#809)

* Rewrite nose tests to use unittest

* Rewrite remaining bare test functions

* Remove print statements from unit tests

* Replace assertEquals with assertEqual

* Fix error due to comparing None with int (#969)

* Use unittest discover instead of nose.core (#810)

* Merge pull request #829 from enthought/fix/ui-panel-alignment

Remove align centre which was causing problems

* Merge pull request #808 from enthought/fix/demo-fixes

A variety of fixes to the Demo app

* Add more tests for Enum Editor (#836)

* Add more tests for Enum Editor

* Add wx EnumEditor tests

* Add missing skipif decorator

* Add issue references to FIXMEs

* Address review comments

* Add check list editor tests (#837)

* Add check list editor tests

* Add wx tests for check list editor

* Simplify helper functions

* Add issue references to FIXMEs

* Address review comments

* Don't rely on empty list behaviour with combobox editor

* Add temporary fix to prevent wx test interactions

* Add set editor tests (#838)

* Add set editor tests

* Simplify helper functions

* Add wx tests for set editor

* Add issue reference to FIXME

* Address review comments

* Expand ordered flag tests

* Add image enum editor tests (#845)

* Add tests for image enum editor

* Docstring fixes

* Address review comments

* Skip tests that don't cleanup properly due to editor issue

* Remove unreliable image_cache checks

* Skip problematic tests on linux

* Address review comments

* Move value mapping from factory to individual editors (#848)

* Move value mapping from factory to individual editors

* Remove factory mapping references from image enum editor

* Remove unused wx helper function

* Address review comments

* Remove test FIXMEs

* Use instantiated tookit

* Merge pull request #850 from enthought/fix-demo-app-description-for-folder

Fix Demo application description if __init__.py or traits_ui_demo.jpg are not found

* BUG: Correctly implement auto-add functionality in ListStrModel. (#860)

* Move format_func, format_str and invalid traits from factory to editor (#859)

* Move format_func and format_str from factory to editor

* Move invalid from factory to editor as invalid_trait_name

* Merge pull request #871 from enthought/fix/segfault-row-reorder

FIX: Make sure new_row is positive

* Merge pull request #873 from enthought/maint-tabular-model

Maint: Normalize row index in TabularModel

* Make sure all UI in tests are disposed (#865)

* Dispose ui in test_visible_when_layout

* Wrap test with create_ui, and store_exceptions_on_all_threads

* Dispose ui and wrap it under store_exceptions... for test_ui

* Use create_ui in test_color_column

* Wrap tests with create_ui and store_exceptions_on_all_threads

* Dispose ui in test_actions

* Consistently dispose UI with create_ui in test_code_editor

* Skip two tests on wx that fail on its own

* Dispose UI in test_table_editor; these tests are failing on their own

* Remove skips; it was the developer's fault in not refreshing their devenv

* Dispose UI in test_csv_editor

* Make sure dispose must be called in test_date_editor

* Make sure dispose is called in test_date_range_editor

* Make sure dispose is called in test_datetime_editor

* Dispose ui in test_instance_editor

* Dispose ui in test_liststr_editor_selection

* Dispose ui in test_range_editor_spinner

* Dispose ui in test_range_editor_text

* Dispose ui in test_tree_editor

* Dispose UI in test_tuple_editor

* One more in test_data_frame_editor

* Remove additional store_exceptions_on_all_threads as they are orthogonal changes

* Experiment removing skips that were added due to test interactions

* Revert "Experiment removing skips that were added due to test interactions"

This reverts commit 7466c03.

* Try removing another workaround

* Revert "Try removing another workaround"

This reverts commit 090c75c.

* Revert inconsequential change to test_color_column

* Add close back just because it was there before - not sure if it is still needed.

* Add more TabularEditor tests (#874)

* Add more tests for Tabular Editor

* Minor wx TabularEditor fix

* Add brief explanation about Rows flag

* Add more ListStrEditor tests (#869)

* Add more tests for ListStrEditor

* Minor wx ListStrEditor fix

* Add gui.process_events to fix pyface2 errors

* Rename TestListStrEditor with adapter test to TestListStrAdapter

* Add docstrings and clarification comments

* Skip tests on Windows due to potential test interactions

* Fix clear_selection usage

* Fix bad TraitListEvent in ListStr and Tabular Editors (#875)

* Fix bad TraitListEvent in ListStr and Tabular Editors

* Remove test FIXMEs

* Fix unexpected format_func in RangeEditor bug (#900)

* Accept format_func, format_str and invalid parameters with RangeEditor

* Add a test to verify same behaviour

* Use kwargs in the signature

* Alternative fix to TabularAdapter crashes when column number reduces (#897)

Co-authored-by: Federico Miorelli <[email protected]>

* Fix eerror when the columns number is reduced

* Workaround slot being called after the UI is disconnected

* destroy control (later) in dispose to prevent slots being called after dispose

* Revert "destroy control (later) in dispose to prevent slots being called after dispose"

This reverts commit 8bb6abd.

* Fix issue number in comment

* Update test name and comments

* Rework test comment

* Rewrite comment and run process_events so that bug appears independently of the workaround

* Add links from TabularEditor and TreeEditor to adapter docs (#917)

* Add links from TabularEditor and TreeEditor to adapter docs

* Fix tree node ref

* Fix Theme pickling (#915)

* Check toolkit before wx import + tests

* Address review comments

* Merge pull request #846 from enthought/maint-test-non-null-toolkit-layout-labels

TST: Add tests for layout and labels using any non-null toolkits
(cherry picked from commit 4398b3d)

Co-authored-by: Ieva <[email protected]>
Co-authored-by: Kit Choi <[email protected]>
Co-authored-by: Robert Kern <[email protected]>
Co-authored-by: Kit Yan Choi <[email protected]>
  • Loading branch information
5 people authored Jul 8, 2020
1 parent ea321a6 commit 1921fc7
Show file tree
Hide file tree
Showing 72 changed files with 5,831 additions and 2,102 deletions.
4 changes: 4 additions & 0 deletions docs/source/traitsui_user_manual/adapters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ are the ListStrEditor, the TabularEditor and the TreeEditor. In this section
we will look more closely at each of these and discuss how they can be
customized as needed.

.. _advanced-tree-node:

The TreeEditor and TreeNodes
============================

Expand Down Expand Up @@ -302,6 +304,8 @@ There are a number of examples of use of the
- :github-demo:`Tree Editor with Renderer <Extras/Tree_editor_with_TreeNodeRenderer.py>`


.. _advanced-tabular-adapter:

The TabularAdapter Class
========================

Expand Down
7 changes: 5 additions & 2 deletions docs/source/traitsui_user_manual/factories_advanced_extra.rst
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,9 @@ TabularAdapter
The tabular editor works in conjunction with an adapter class, derived from
TabularAdapter. The tabular adapter interfaces between the tabular editor and
the data being displayed. The tabular adapter is the reason for the flexibility
and power of the tabular editor to display a wide variety of data.
and power of the tabular editor to display a wide variety of data. For more
detailed information about the TabularAdapter class please see
:ref:`advanced-tabular-adapter`.

The most important attribute of TabularAdapter is **columns**, which is list of
columns to be displayed. Each entry in the **columns** list can be either a
Expand Down Expand Up @@ -940,7 +942,8 @@ Defining Nodes
::::::::::::::

For details on the attributes of the TreeNode class, refer to the *Traits API
Reference*.
Reference*. More information about the TreeNode class is also available in
:ref:`advanced-tree-node`.

You must specify the classes whose instances the node type applies to. Use the
**node_for** attribute of TreeNode to specify a list of classes; often, this
Expand Down
15 changes: 10 additions & 5 deletions etstool.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,17 @@ def test(runtime, toolkit, environment):
parameters = get_parameters(runtime, toolkit, environment)
environ = environment_vars.get(toolkit, {}).copy()
environ['PYTHONUNBUFFERED'] = "1"

if toolkit == "wx":
environ["EXCLUDE_TESTS"] = "qt"
elif toolkit in {"pyqt", "pyqt5", "pyside", "pyside2"}:
environ["EXCLUDE_TESTS"] = "wx"
else:
environ["EXCLUDE_TESTS"] = "(wx|qt)"

commands = [
"edm run -e {environment} -- coverage run -p -m nose.core -v traitsui.tests --nologcapture"]
# extra tests for qt
if toolkit in {'pyqt', 'pyside', 'pyqt5'}:
commands.append(
"edm run -e {environment} -- coverage run -p -m nose.core -v traitsui.qt4.tests --nologcapture")
"edm run -e {environment} -- coverage run -p -m unittest discover -v traitsui"
]

# We run in a tempdir to avoid accidentally picking up wrong traitsui
# code from a local dir. We need to ensure a good .coveragerc is in
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
"""
These demonstrations show off some of the more advanced features of and
TraitsUI.
"""
1 change: 0 additions & 1 deletion examples/demo/Dynamic_Forms/__init__.py

This file was deleted.

1 change: 1 addition & 0 deletions examples/demo/Dynamic_Forms/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implementations of dynamic form behavior using TraitsUI
51 changes: 51 additions & 0 deletions examples/demo/Standard_Editors/DatetimeEditor_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright (c) 2020, Enthought, Inc.
# License: BSD Style.

"""
A Traits UI editor that edits a datetime panel.
"""
import datetime

from traits.api import HasTraits, Datetime, Str
from traitsui.api import View, Item, Group


class DateEditorDemo(HasTraits):
""" Demo class to show Datetime editors. """
datetime = Datetime()
info_string = Str('The editors for Traits Datetime objects.')

view = View(
Item(
'info_string',
show_label=False,
style='readonly',
),
Group(
Item(
'datetime',
label='Simple date editor',
),
Item(
'datetime',
style='readonly',
label='ReadOnly editor',
),
label='Default settings for editors',
),
resizable=True,
)

def _datetime_changed(self):
""" Print each time the date value is changed in the editor. """
print(self.datetime)


#-- Set Up The Demo ------------------------------------------------------

demo = DateEditorDemo(
datetime=datetime.datetime.now()
)

if __name__ == "__main__":
demo.configure_traits()
1 change: 1 addition & 0 deletions examples/demo/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. image:: traits_ui_demo.jpg
15 changes: 8 additions & 7 deletions examples/tutorials/tutor.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ def main(root_dir):
if __name__ == '__main__':

# Validate the command line arguments:
if len(sys.argv) != 2:
if len(sys.argv) > 2:
print(usage)
sys.exit(1)

root_dir = sys.argv[1]
try:
main(root_dir)
except NameError as e:
print(e)
print(usage)
# Determine the root path to use for the tutorial files:
if len(sys.argv) == 2:
root_dir = sys.argv[1]
else:
root_dir = os.getcwd()

main(root_dir)
44 changes: 44 additions & 0 deletions traitsui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,47 @@
"pyside": ["pyside>=1.2", "pygments"],
"demo": ["configobj", "docutils"],
}


# ============================= Test Loader ==================================
def load_tests(loader, standard_tests, pattern):
""" Custom test loading function that enables test filtering using regex
exclusion pattern.
Parameters
----------
loader : unittest.TestLoader
The instance of test loader
standard_tests : unittest.TestSuite
Tests that would be loaded by default from this module (no tests)
pattern : str
An inclusion pattern used to match test files (test*.py default)
Returns
-------
filtered_package_tests : unittest.TestSuite
TestSuite representing all package tests that did not match specified
exclusion pattern.
"""
from os import environ
from os.path import dirname
from traitsui.tests._tools import filter_tests
from unittest import TestSuite

# Make sure the right toolkit is up and running before importing tests
from traitsui.toolkit import toolkit
toolkit()

this_dir = dirname(__file__)
package_tests = loader.discover(start_dir=this_dir, pattern=pattern)

exclusion_pattern = environ.get("EXCLUDE_TESTS", None)
if exclusion_pattern is None:
return package_tests

filtered_package_tests = TestSuite()
for test_suite in package_tests:
filtered_test_suite = filter_tests(test_suite, exclusion_pattern)
filtered_package_tests.addTest(filtered_test_suite)

return filtered_package_tests
30 changes: 27 additions & 3 deletions traitsui/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ class Editor(HasPrivateTraits):
#: The trait the editor is editing (not its value, but the trait itself):
value_trait = Property()

#: Function to use for string formatting
format_func = Callable()

#: Format string to use for formatting (used if **format_func** is not set)
format_str = Str()

#: The extended trait name of the trait containing editor invalid state
#: status:
invalid_trait_name = Str()

#: The current editor invalid state status:
invalid = Bool(False)

Expand Down Expand Up @@ -183,7 +193,12 @@ def set_focus(self):
def string_value(self, value, format_func=None):
""" Returns the text representation of a specified object trait value.
This simply delegates to the factory's `string_value` method.
If the **format_func** attribute is set on the editor, then this method
calls that function to do the formatting. If the **format_str**
attribute is set on the editor, then this method uses that string for
formatting. If neither attribute is set, then this method just calls
the appropriate text type to format.
Sub-classes may choose to override the default implementation.
Parameters
Expand All @@ -193,7 +208,16 @@ def string_value(self, value, format_func=None):
format_func : callable or None
A function that takes a value and returns a string.
"""
return self.factory.string_value(value, format_func)
if self.format_func is not None:
return self.format_func(value)

if self.format_str != "":
return self.format_str % value

if format_func is not None:
return format_func(value)

return str(value)

def restore_prefs(self, prefs):
""" Restores saved user preference information for the editor.
Expand Down Expand Up @@ -470,7 +494,7 @@ def __init__(self, parent, **traits):
raise

# Synchronize the application invalid state status with the editor's:
self.sync_value(self.factory.invalid, "invalid", "from")
self.sync_value(self.invalid_trait_name, "invalid", "from")

# ------------------------------------------------------------------------
# private methods
Expand Down
44 changes: 12 additions & 32 deletions traitsui/editor_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ def simple_editor(self, ui, object, name, description, parent):
object=object,
name=name,
description=description,
format_func=self.format_func,
format_str=self.format_str,
invalid_trait_name=self.invalid,
)

def custom_editor(self, ui, object, name, description, parent):
Expand All @@ -147,6 +150,9 @@ def custom_editor(self, ui, object, name, description, parent):
object=object,
name=name,
description=description,
format_func=self.format_func,
format_str=self.format_str,
invalid_trait_name=self.invalid,
)

def text_editor(self, ui, object, name, description, parent):
Expand All @@ -159,6 +165,9 @@ def text_editor(self, ui, object, name, description, parent):
object=object,
name=name,
description=description,
format_func=self.format_func,
format_str=self.format_str,
invalid_trait_name=self.invalid,
)

def readonly_editor(self, ui, object, name, description, parent):
Expand All @@ -171,6 +180,9 @@ def readonly_editor(self, ui, object, name, description, parent):
object=object,
name=name,
description=description,
format_func=self.format_func,
format_str=self.format_str,
invalid_trait_name=self.invalid,
)

# -------------------------------------------------------------------------
Expand Down Expand Up @@ -199,26 +211,6 @@ def _get_toolkit_editor(cls, class_name):
raise e
return None

def string_value(self, value, format_func=None):
""" Returns the text representation of a specified object trait value.
If the **format_func** attribute is set on the editor factory, then
this method calls that function to do the formatting. If the
**format_str** attribute is set on the editor factory, then this
method uses that string for formatting. If neither attribute is
set, then this method just calls the appropriate text type to format.
"""
if self.format_func is not None:
return self.format_func(value)

if self.format_str != "":
return self.format_str % value

if format_func is not None:
return format_func(value)

return str(value)

# -------------------------------------------------------------------------
# Property getters
# -------------------------------------------------------------------------
Expand Down Expand Up @@ -309,15 +301,3 @@ class EditorWithListFactory(EditorFactory):

#: Name of the trait on 'object' containing the enumeration data
name = Str()

#: Fired when the **values** trait has been updated:
values_modified = Event()

def _values_changed(self):
""" Recomputes the mappings whenever the **values** trait is changed.
"""
self._names, self._mapping, self._inverse_mapping = enum_values_changed(
self.values, strfunc=self.string_value
)

self.values_modified = True
8 changes: 4 additions & 4 deletions traitsui/editors/array_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ def _one_dim_view(self, object, style, width, trait):
content = []
shape = object.shape
items = []
format_func = self.editor.factory.format_func
format_str = self.editor.factory.format_str
format_func = self.editor.format_func
format_str = self.editor.format_str
for i in range(shape[0]):
name = "f%d" % i
self.add_trait(
Expand Down Expand Up @@ -146,8 +146,8 @@ def _one_dim_view(self, object, style, width, trait):
def _two_dim_view(self, object, style, width, trait):
content = []
shape = object.shape
format_func = self.editor.factory.format_func
format_str = self.editor.factory.format_str
format_func = self.editor.format_func
format_str = self.editor.format_str
for i in range(shape[0]):
items = []
for j in range(shape[1]):
Expand Down
12 changes: 12 additions & 0 deletions traitsui/editors/csv_list_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,9 @@ def simple_editor(self, ui, object, name, description, parent):
object=object,
name=name,
description=description,
format_func=self.format_func,
format_str=self.format_str,
invalid_trait_name=self.invalid,
)

def custom_editor(self, ui, object, name, description, parent):
Expand All @@ -370,6 +373,9 @@ def custom_editor(self, ui, object, name, description, parent):
object=object,
name=name,
description=description,
format_func=self.format_func,
format_str=self.format_str,
invalid_trait_name=self.invalid,
)

def text_editor(self, ui, object, name, description, parent):
Expand All @@ -383,6 +389,9 @@ def text_editor(self, ui, object, name, description, parent):
object=object,
name=name,
description=description,
format_func=self.format_func,
format_str=self.format_str,
invalid_trait_name=self.invalid,
)

def readonly_editor(self, ui, object, name, description, parent):
Expand All @@ -396,4 +405,7 @@ def readonly_editor(self, ui, object, name, description, parent):
object=object,
name=name,
description=description,
format_func=self.format_func,
format_str=self.format_str,
invalid_trait_name=self.invalid,
)
Loading

0 comments on commit 1921fc7

Please sign in to comment.