Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
081745c
adding enum editor implementations and replacing some old tests
aaronayres35 Sep 3, 2020
ea7cc90
update docstrings
aaronayres35 Sep 3, 2020
d04c765
refactor by creating a generic _IndexedEditor class that is subclasse…
aaronayres35 Sep 3, 2020
764da1a
using previous refactor on qt as well
aaronayres35 Sep 3, 2020
08b76cc
adding text handling (need to fix 2 failing tests on wx)
aaronayres35 Sep 4, 2020
139a1ba
making suggested change to _IndexedEditor
aaronayres35 Sep 4, 2020
f4a3704
fixing broken tests
aaronayres35 Sep 4, 2020
e65d1f3
removing unneeded code from test_enum_editor
aaronayres35 Sep 4, 2020
e4cf8a1
adding a bunch of docstrings
aaronayres35 Sep 4, 2020
b38d373
more docstrings
aaronayres35 Sep 4, 2020
97bd3f8
raise if try to use anything but locator.Index for now in _SourceWith…
aaronayres35 Sep 4, 2020
6cf6825
flake8
aaronayres35 Sep 4, 2020
e1b6ae6
Merge branch 'master' into ui-tester-updates-EnumEditor
aaronayres35 Sep 4, 2020
983c3a0
making some of the suggested changes
aaronayres35 Sep 4, 2020
b94e05c
split mouse_click_child_in_panel into two functions: 1 for radiobutto…
aaronayres35 Sep 4, 2020
ef66605
making suggested changes
aaronayres35 Sep 4, 2020
6bd3512
fixing test failures on wx due to changes from pr 1193
aaronayres35 Sep 4, 2020
b3547c6
making a seperate key_click_combobox function (at least for now)
aaronayres35 Sep 7, 2020
36bcc62
flake8
aaronayres35 Sep 8, 2020
a0b1fa4
fixing indexing error on qt
aaronayres35 Sep 14, 2020
8b8073a
adding docstring
aaronayres35 Sep 14, 2020
d48201c
fixing the index error on wx
aaronayres35 Sep 14, 2020
9be6345
first round of suggested changes
aaronayres35 Sep 14, 2020
22f0035
making new key_click_text_entry / key_click_combobox refactor suggestion
aaronayres35 Sep 14, 2020
06e28d9
more suggested changed and fixing setting row major trait in test
aaronayres35 Sep 14, 2020
09ceb0b
adding tests for when no entry in the enum is selected. (currently f…
aaronayres35 Sep 14, 2020
120c67f
updating test (still fails)
aaronayres35 Sep 14, 2020
bd71f8a
more suggested changes and skipping the failing test until it is disc…
aaronayres35 Sep 14, 2020
c85078d
Merge branch 'master' into ui-tester-updates-EnumEditor
aaronayres35 Sep 14, 2020
e9814d1
fixing test for None selected with List editor
aaronayres35 Sep 15, 2020
ff1e837
more suggested changes
aaronayres35 Sep 15, 2020
eccda85
flake8
aaronayres35 Sep 15, 2020
11ad4f4
Merge branch 'master' into ui-tester-updates-EnumEditor
aaronayres35 Sep 15, 2020
e96b9a5
adding refactor for column_major to row major index logic
aaronayres35 Sep 15, 2020
99a2d6f
Merge branch 'ui-tester-updates-EnumEditor' of https://github.com/ent…
aaronayres35 Sep 15, 2020
bc0fa36
forgot an init.py
aaronayres35 Sep 15, 2020
9775f92
fixing layout helper function and adding tests for it
aaronayres35 Sep 15, 2020
6542403
last fix was actually still broken
aaronayres35 Sep 15, 2020
5f1f2fa
adding an algorithm explanation to docstring for column_major_to_row_…
aaronayres35 Sep 15, 2020
221cef9
removing now redundant inline comments
aaronayres35 Sep 15, 2020
529bfbb
making suggested changes
aaronayres35 Sep 15, 2020
7ca5c4b
Merge branch 'master' into ui-tester-updates-EnumEditor
aaronayres35 Sep 15, 2020
2c0a390
adding another key_click_text_ctrl to key_click_text_entry name change
aaronayres35 Sep 15, 2020
7453213
skipping test on windows and wx as behavior is different
aaronayres35 Sep 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions traitsui/testing/tester/common_ui_targets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Copyright (c) 2005-2020, Enthought, Inc.
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only
# under the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
#
""" This module contains targets for UIWrapper so that the logic related to
them can be reused.
To use the logic in these objects, if the class in this module is a base class
(indicated by leading _Base) they simply need to subclass this class, override
any necessary traits, and then call the register method.
"""


class _BaseSourceWithLocation:
""" Wrapper base class to hold locator information together with a source
(typically an editor). This is useful for cases in which the location
information is still necessary when performing actions such as a mouse
click or key click.

For example, an Enum editor and an index.
This class is meant to be subclassed for specific usecases, and the
class level attributes overridden.
"""

# The type of the source object on which the location information will be
# evaluated on
source_class = None
# The type of the locator object that provides location information.
# (e.g. locator.Index)
locator_class = None
# the handlers we want to register for the given source_class
# must be given as a list of tuples where the first element is the
# interaction class (e.g. command.MouseClick) and the second is the
# actual handler function. See registry.TargetRegistry.register_handler
# for the signature of the callable.
handlers = []

def __init__(self, source, location):
"""
Parameters
----------
source : instance of source_class
The source object. Typically this is an editor.
location : instance of locator_class
The location information of interest
"""
self.source = source
self.location = location

@classmethod
def register(cls, registry):
""" Class method to register interactions on a
_SourceWithLocation for the given registry. It is expected that this
class method will be called by subclasses, and thus interactions would
be registered to subclasses rather than the base class.

If there are any conflicts, an error will occur.

Parameters
----------
registry : TargetRegistry
The registry being registered to.
"""
registry.register_solver(
target_class=cls.source_class,
locator_class=cls.locator_class,
solver=lambda wrapper, location: cls(wrapper.target, location),
)
for interaction_class, handler in cls.handlers:
registry.register_handler(
target_class=cls,
interaction_class=interaction_class,
handler=handler
)
Empty file.
95 changes: 95 additions & 0 deletions traitsui/testing/tester/editors/layout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Copyright (c) 2005-2020, Enthought, Inc.
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only
# under the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
#
""" This module contains helper functions for working with layouts inside an
editor. For example, converting indices so they count through the layout
appropraitely.
"""


def column_major_to_row_major(index, n, num_rows, num_cols):
""" Helper function to convert an index of a grid layout so that the
index counts over the grid in the correct direction.
In TraitsUI, grids are typically populated in row major order, however,
the elements can be assigned to each entry in the grid so that when
displayed they appear in column major order. To access the correct element
we may need to convert a column-major based index into a row-major one.

Parameters
----------
index : int
the index of interest
n : int
The total number of elements in the layout
num_rows : int
the number of rows in the layout
num_cols : int
the number of columns in the layout

Returns
-------
int
The converted index (now corresponding to row_major order)

Notes
-----
Since elements are populated in row major order, the resulting grid ends
up having at most its last row as incomplete. The general approach for the
algorithm is to find the coordinates as if we had counted through the
grid in column major order, and then convert that back to a row major
index. The complications come from hte fact that the last row may be
missing entries.
Consider the example (n=17, num_row=4, num_cols=5)
0 4 8 11 14
1 5 9 12 15
2 6 10 13 16
3 7 / / /
Row major order is 0, 4, 11, 14, 1, 5, ...

If the given index is 7 then we are in a column of the matrix where
all rows are full. This corresponds to the else branch below. From here,
we simply find the (i,j) coordiantes of the entry 7 above, with the upper
left corner representing (0,0). Thus, (i,j) = (3,1). Now, to convert
this to a row major index, we can simply take i * num_cols + j.

If the given index is 15, then we are in a column where the last row is
missing an entry. See the if branch below. In the case the logic used
before won't work, because it would expect the grid to be filled. (i.e.
if one tried to do this in the same way you would get (i,j) = (3,4)).
To adderess this we break up the grid into two grids:
0 4 and 8 11 14
1 5 9 12 15
2 6 10 13 16
3 7
we find the (i2,j2) coordiantes of the entry 15 above in grid2, with the
upper left corner of grid2 representing (0,0). Hence, (i2,j2) = (1,2).
We then find that index if we had counted in row major order for grid2,
which would be i2 * num_empty_entries_last_row + j2 = 5, and add that to
however many elements would need to be counted over from grid one to reach
element 15 if we had been counting in row major order. Which is
(num_cols - num_empty_entries_last_row)*(i2+1).
"""
if index > n:
raise ValueError("Index is higher number of elements in layout")
num_empty_entries_last_row = num_cols * num_rows - n
if num_empty_entries_last_row < 0:
raise ValueError("n can not be greater than num_cols * num_rows")

if index > num_rows * (num_cols - num_empty_entries_last_row):
num_entries_grid1 = num_rows * (num_cols - num_empty_entries_last_row)
new_index = index - num_entries_grid1
i2 = new_index % (num_rows - 1)
j2 = new_index // (num_rows - 1)
return (num_cols - num_empty_entries_last_row)*(i2+1) + \
(i2 * num_empty_entries_last_row + j2)
else:
i = index % num_rows
j = index // num_rows
return i * num_cols + j
Empty file.
129 changes: 129 additions & 0 deletions traitsui/testing/tester/editors/tests/test_layout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Copyright (c) 2005-2020, Enthought, Inc.
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only
# under the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
#
import unittest

from traitsui.testing.tester.editors.layout import column_major_to_row_major


class TestLayout(unittest.TestCase):

def test_column_major_index_too_large(self):
# Test when the index is too large for the total number of elements
# The indices would look like:
# 0 2 3 4
# 1 / / /
with self.assertRaises(ValueError):
column_major_to_row_major(
index=10,
n=5,
num_rows=2,
num_cols=4,
)

def test_column_major_index_index_overhanging(self):
# This is the layout for displaying numbers from 0-9 with column
# major setup:
# 0 3 6 8
# 1 4 7 9
# 2 5 / /
# The index should be populated (row first) in this order:
# 0, 3, 6, 8, 1, 4, 7, 9, 2, 5
actual = column_major_to_row_major(
index=9,
n=10,
num_rows=3,
num_cols=4,
)
self.assertEqual(actual, 7)

def test_column_major_index_in_grid_first_row(self):
# Test when the index is small enough to be within the upper, filled
# grid.
# This is the layout for displaying numbers from 0-9 with column
# major setup:
# 0 3 6 8
# 1 4 7 9
# 2 5 / /
# The index should be populated (row first) in this order:
# 0, 3, 6, 8, 1, 4, 7, 9, 2, 5
actual = column_major_to_row_major(
index=6,
n=10,
num_rows=3,
num_cols=4,
)
self.assertEqual(actual, 2)

def test_column_major_index_in_grid_last_row(self):
# Test when the index is small enough to be within the upper, filled
# grid.
# This is the layout for displaying numbers from 0-9 with column
# major setup:
# 0 3 6 8
# 1 4 7 9
# 2 5 / /
# The index should be populated (row first) in this order:
# 0, 3, 6, 8, 1, 4, 7, 9, 2, 5
actual = column_major_to_row_major(
index=4,
n=10,
num_rows=3,
num_cols=4,
)
self.assertEqual(actual, 5)

def test_column_major_index_last_row(self):
# Test when the index is in the last row
# This is the layout for displaying numbers from 0-9 with column
# major setup:
# 0 3 6 8
# 1 4 7 9
# 2 5 / /
# The index should be populated (row first) in this order:
# 0, 3, 6, 8, 1, 4, 7, 9, 2, 5
actual = column_major_to_row_major(
index=2,
n=10,
num_rows=3,
num_cols=4,
)
self.assertEqual(actual, 8)

def test_column_major_index_long_overhang(self):
# This is the layout for displaying numbers from 0-9 with column
# major setup:
# 0 2 3 4
# 1 / / /
# The index should be populated (row first) in this order:
# 0, 2, 3, 4, 1
actual = column_major_to_row_major(
index=4,
n=5,
num_rows=2,
num_cols=4,
)
self.assertEqual(actual, 3)

def test_column_major_index_full_grid(self):
# This is the layout for displaying numbers from 0-9 with column
# major setup:
# 0 3 6 9 12
# 1 4 7 10 13
# 2 5 8 11 14
# The index should be populated (row first) in this order:
# 0, 3, 6, 9, 12, 1, 4, 7, 10, 13, 2, 5, 8, 11, 14
actual = column_major_to_row_major(
index=11,
n=15,
num_rows=3,
num_cols=5,
)
self.assertEqual(actual, 13)
4 changes: 4 additions & 0 deletions traitsui/testing/tester/qt4/default_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from traitsui.testing.tester.qt4.implementation import (
button_editor,
check_list_editor,
enum_editor,
instance_editor,
list_editor,
range_editor,
Expand All @@ -40,6 +41,9 @@ def get_default_registry():
# CheckListEditor
check_list_editor.register(registry)

# EnumEditor
enum_editor.register(registry)

# TextEditor
text_editor.register(registry)

Expand Down
Loading