import unittest from test.support import import_helper from test.support import threading_helper readline = import_helper.import_module("readline") @threading_helper.requires_working_threading() class TestReadlineRaces(unittest.TestCase): def test_completer_delims_get_set(self): def worker(): for _ in range(100): readline.get_completer_delims() readline.set_completer_delims( ' \t\n`@#%^&*()=+[{]}\\|;:\'",<>?') readline.set_completer_delims( ' \t\n`@#%^&*()=+[{]}\\|;:\'",<>?') readline.get_completer_delims() threading_helper.run_concurrently(worker, nthreads=40) # get_completer()/get_pre_input_hook() must take the module critical # section like their setters do; otherwise reading and Py_NewRef-ing the # stored hook races the setter replacing it (gh-153291). def test_completer_get_set(self): def setter(): for _ in range(1000): readline.set_completer(lambda text, state: None) readline.set_completer(None) def getter(): for _ in range(1000): readline.get_completer() original = readline.get_completer() self.addCleanup(readline.set_completer, original) threading_helper.run_concurrently([setter] * 2 + [getter] * 6) @unittest.skipUnless(hasattr(readline, "set_pre_input_hook"), "needs readline.set_pre_input_hook") def test_pre_input_hook_get_set(self): def setter(): for _ in range(1000): readline.set_pre_input_hook(lambda: None) readline.set_pre_input_hook(None) def getter(): for _ in range(1000): readline.get_pre_input_hook() original = readline.get_pre_input_hook() self.addCleanup(readline.set_pre_input_hook, original) threading_helper.run_concurrently([setter] * 2 + [getter] * 6) if __name__ == "__main__": unittest.main()