Skip to content

Commit af06456

Browse files
authored
Merge pull request #111 from jkonecny12/master-support-disable-concurrent-check-for-UIScreen
Add support to disable concurrency check for UIScreen
2 parents cd3fd2d + 741ae90 commit af06456

File tree

4 files changed

+122
-0
lines changed

4 files changed

+122
-0
lines changed

simpleline/input/input_handler.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ def __init__(self, callback=None, source=None):
5353
self._skip_concurrency_check = False
5454
self._source = source
5555

56+
self._register_input_ready_signal()
57+
58+
def _register_input_ready_signal(self):
5659
App.get_event_loop().register_signal_handler(InputReadySignal,
5760
self._input_received_handler)
5861

simpleline/render/screen/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ def title(self, title):
8888
"""
8989
self._title = title
9090

91+
@property
92+
def input_manager(self):
93+
"""Get input manager.
94+
95+
The input manager could be used to tweak input settings.
96+
"""
97+
return self._input_manager
98+
9199
@property
92100
def password_func(self):
93101
"""Get password function.

simpleline/render/screen/input_manager.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def __init__(self, ui_screen):
4747
self._ui_screen = ui_screen
4848
self._input_error_counter = 0
4949
self._input_error_threshold = 5
50+
self._skip_concurrency_check = False
5051
self._input_args = None
5152

5253
@property
@@ -63,6 +64,25 @@ def input_error_threshold_exceeded(self):
6364
errors = self._input_error_counter % self._input_error_threshold
6465
return errors == 0
6566

67+
@property
68+
def skip_concurrency_check(self):
69+
"""Should the concurrency check be skipped?
70+
71+
:returns bool: True if the check should be skipped.
72+
"""
73+
return self._skip_concurrency_check
74+
75+
@skip_concurrency_check.setter
76+
def skip_concurrency_check(self, value):
77+
"""Set if the concurrency check should be skipped when asking for user input.
78+
79+
WARNING: Use this option with caution. When the concurrency check is disabled you
80+
can easily get to unexpected behavior which is hard to debug.
81+
82+
:param bool value: True to skip the concurrency check.
83+
"""
84+
self._skip_concurrency_check = value
85+
6686
def get_input_blocking(self, message, hidden):
6787
"""Get blocking input from the user.
6888
@@ -79,6 +99,7 @@ def get_input_blocking(self, message, hidden):
7999
else:
80100
handler = InputHandler(source=self)
81101

102+
handler.skip_concurrency_check = self._skip_concurrency_check
82103
handler.get_input(message)
83104
handler.wait_on_input()
84105
return handler.value
@@ -102,6 +123,7 @@ def get_input(self, args=None):
102123
if self._ui_screen.password_func:
103124
handler.set_pass_func(self._ui_screen.password_func)
104125

126+
handler.skip_concurrency_check = self._skip_concurrency_check
105127
handler.set_callback(self.process_input)
106128
handler.get_input(prompt)
107129

tests/units/main/adv_widgets_test.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,100 @@
2323
from unittest.mock import patch
2424
from io import StringIO
2525

26+
from simpleline.render.screen import UIScreen
27+
from simpleline.input.input_handler import InputHandler
2628
from simpleline.render.adv_widgets import GetInputScreen, GetPasswordInputScreen
2729

2830
from .. import UtilityMixin
2931

3032

33+
class InputHandlerMock(InputHandler):
34+
"""Dummy InputHandler instance.
35+
36+
This class based on InputHandler has all threading logic disabled for simpler testing.
37+
"""
38+
def _register_input_ready_signal(self):
39+
pass
40+
41+
def get_input(self, prompt):
42+
pass
43+
44+
def wait_on_input(self):
45+
pass
46+
47+
48+
class UIScreen_TestCase(unittest.TestCase):
49+
@patch('simpleline.render.screen.input_manager.InputHandler')
50+
def test_uiscreen_disable_concurrency_check(self, input_handler_class_mock):
51+
# Replace default InputHandler instance created by InputManager by our mock to have
52+
# it stored after use.
53+
input_handler_instance_mock = InputHandlerMock()
54+
input_handler_class_mock.return_value = input_handler_instance_mock
55+
56+
screen = UIScreen()
57+
input_manager = screen.input_manager
58+
input_manager.skip_concurrency_check = True
59+
screen.get_user_input("test")
60+
61+
self.assertTrue(screen.input_manager.skip_concurrency_check)
62+
# Check that the created InputHandler instance has the flag correctly set.
63+
# We don't need to check the concurrency check functionality, it is tested
64+
# elsewhere already.
65+
self.assertTrue(input_handler_instance_mock.skip_concurrency_check)
66+
67+
@patch('simpleline.render.screen.input_manager.InputHandler')
68+
def test_uiscreen_password_disable_concurrency_check(self, input_handler_class_mock):
69+
# Replace default InputHandler instance created by InputManager by our mock to have
70+
# it stored after use.
71+
input_handler_instance_mock = InputHandlerMock()
72+
input_handler_class_mock.return_value = input_handler_instance_mock
73+
74+
screen = GetPasswordInputScreen(message="Test prompt")
75+
input_manager = screen.input_manager
76+
input_manager.skip_concurrency_check = True
77+
screen.get_user_input("test")
78+
79+
self.assertTrue(screen.input_manager.skip_concurrency_check)
80+
# Check that the created InputHandler instance has the flag correctly set.
81+
# We don't need to check the concurrency check functionality, it is tested
82+
# elsewhere already.
83+
self.assertTrue(input_handler_instance_mock.skip_concurrency_check)
84+
85+
@patch('simpleline.render.screen.input_manager.InputHandler')
86+
def test_uiscreen_non_blocking_input_disable_concurrency_check(self, input_handler_class_mock):
87+
# Replace default InputHandler instance created by InputManager by our mock to have
88+
# it stored after use.
89+
input_handler_instance_mock = InputHandlerMock()
90+
input_handler_class_mock.return_value = input_handler_instance_mock
91+
92+
screen = UIScreen()
93+
input_manager = screen.input_manager
94+
input_manager.skip_concurrency_check = True
95+
screen.get_input_with_error_check("test")
96+
97+
self.assertTrue(screen.input_manager.skip_concurrency_check)
98+
# Check that the created InputHandler instance has the flag correctly set.
99+
# We don't need to check the concurrency check functionality, it is tested
100+
# elsewhere already.
101+
self.assertTrue(input_handler_instance_mock.skip_concurrency_check)
102+
103+
@patch('simpleline.render.screen.input_manager.InputHandler')
104+
def test_uiscreen_default_concurrency_check(self, input_handler_class_mock):
105+
# Replace default InputHandler instance created by InputManager by our mock to have
106+
# it stored after use.
107+
input_handler_instance_mock = InputHandlerMock()
108+
input_handler_class_mock.return_value = input_handler_instance_mock
109+
110+
screen = UIScreen()
111+
screen.get_user_input("test")
112+
113+
self.assertFalse(screen.input_manager.skip_concurrency_check)
114+
# Check that the created InputHandler instance has the flag correctly set.
115+
# We don't need to check the concurrency check functionality, it is tested
116+
# elsewhere already.
117+
self.assertFalse(input_handler_instance_mock.skip_concurrency_check)
118+
119+
31120
@patch('simpleline.input.input_handler.InputHandlerRequest._get_input')
32121
@patch('sys.stdout', new_callable=StringIO)
33122
class AdvWidgets_TestCase(unittest.TestCase, UtilityMixin):

0 commit comments

Comments
 (0)