Skip to content

Commit 1a21831

Browse files
authored
Merge pull request #122 from jkonecny12/1.1-add-disable-concurrency-check
Add support to disable concurrency check
2 parents 0bbf959 + 9965045 commit 1a21831

File tree

4 files changed

+122
-1
lines changed

4 files changed

+122
-1
lines changed

simpleline/input/input_handler.py

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

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

simpleline/render/screen/__init__.py

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

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

simpleline/render/screen/input_manager.py

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

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

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

101+
handler.skip_concurrency_check = self._skip_concurrency_check
81102
handler.get_input(message)
82103
handler.wait_on_input()
83104
return handler.value
@@ -101,6 +122,7 @@ def get_input(self, args=None):
101122
if self._ui_screen.password_func:
102123
handler.set_pass_func(self._ui_screen.password_func)
103124

125+
handler.skip_concurrency_check = self._skip_concurrency_check
104126
handler.set_callback(self.process_input)
105127
handler.get_input(prompt)
106128

tests/simpleline_tests/adv_widgets_test.py

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,98 @@
2323
from io import StringIO
2424

2525
from . import UtilityMixin
26-
26+
from simpleline.render.screen import UIScreen
27+
from simpleline.input.input_handler import InputHandler
2728
from simpleline.render.adv_widgets import GetInputScreen, GetPasswordInputScreen
2829

2930

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

0 commit comments

Comments
 (0)