def test_file_not_in_folder(self): # Test with and without trailing slash ret = LocalSourcesWatcher._file_is_in_folder("/a/b/c/foo.py", "/d/e/f/") self.assertFalse(ret) ret = LocalSourcesWatcher._file_is_in_folder("/a/b/c/foo.py", "/d/e/f") self.assertFalse(ret)
def test_file_in_subfolder(self): # Test with and without trailing slash ret = LocalSourcesWatcher._file_is_in_folder("/a/b/c/foo.py", "/a") self.assertTrue(ret) ret = LocalSourcesWatcher._file_is_in_folder("/a/b/c/foo.py", "/a/") self.assertTrue(ret) ret = LocalSourcesWatcher._file_is_in_folder("/a/b/c/foo.py", "/a/b") self.assertTrue(ret) ret = LocalSourcesWatcher._file_is_in_folder("/a/b/c/foo.py", "/a/b/") self.assertTrue(ret)
def test_config_watcherType(self, _): """Test server.fileWatcherType""" config.set_option("server.fileWatcherType", "none") self.assertIsNone(LocalSourcesWatcher.get_file_watcher_class()) config.set_option("server.fileWatcherType", "poll") if LocalSourcesWatcher.get_file_watcher_class() is not None: self.assertEquals( LocalSourcesWatcher.get_file_watcher_class().__name__, "PollingFileWatcher", ) config.set_option("server.fileWatcherType", "watchdog") if LocalSourcesWatcher.get_file_watcher_class() is not None: self.assertEquals( LocalSourcesWatcher.get_file_watcher_class().__name__, "EventBasedFileWatcher", ) config.set_option("server.fileWatcherType", "auto") self.assertIsNotNone(LocalSourcesWatcher.get_file_watcher_class()) if sys.modules["streamlit.watcher.EventBasedFileWatcher"] is not None: self.assertEquals( LocalSourcesWatcher.get_file_watcher_class().__name__, "EventBasedFileWatcher", ) else: self.assertEquals( LocalSourcesWatcher.get_file_watcher_class().__name__, "PollingFileWatcher", )
def _create_app_session(self, ws: WebSocketHandler) -> AppSession: """Register a connected browser with the server. Parameters ---------- ws : _BrowserWebSocketHandler The newly-connected websocket handler. Returns ------- AppSession The newly-created AppSession for this browser connection. """ session_data = SessionData(self._main_script_path, self._command_line) local_sources_watcher = LocalSourcesWatcher(session_data) session = AppSession( ioloop=self._ioloop, session_data=session_data, uploaded_file_manager=self._uploaded_file_mgr, message_enqueued_callback=self._enqueued_some_message, local_sources_watcher=local_sources_watcher, ) LOGGER.debug("Created new session for ws %s. Session ID: %s", id(ws), session.id) assert (session.id not in self._session_info_by_id ), f"session.id '{session.id}' registered multiple times!" self._session_info_by_id[session.id] = SessionInfo(ws, session) self._set_state(State.ONE_OR_MORE_BROWSERS_CONNECTED) self._has_connection.notify_all() return session
async def does_script_run_without_error(self) -> Tuple[bool, str]: """Load and execute the app's script to verify it runs without an error. Returns ------- (True, "ok") if the script completes without error, or (False, err_msg) if the script raises an exception. """ session_data = SessionData(self._main_script_path, self._command_line) local_sources_watcher = LocalSourcesWatcher(session_data) session = AppSession( ioloop=self._ioloop, session_data=session_data, uploaded_file_manager=self._uploaded_file_mgr, message_enqueued_callback=self._enqueued_some_message, local_sources_watcher=local_sources_watcher, ) try: session.request_rerun(None) now = time.perf_counter() while (SCRIPT_RUN_WITHOUT_ERRORS_KEY not in session.session_state and (time.perf_counter() - now) < SCRIPT_RUN_CHECK_TIMEOUT): await tornado.gen.sleep(0.1) if SCRIPT_RUN_WITHOUT_ERRORS_KEY not in session.session_state: return False, "timeout" ok = session.session_state[SCRIPT_RUN_WITHOUT_ERRORS_KEY] msg = "ok" if ok else "error" return ok, msg finally: session.shutdown()
def test_script_and_2_modules_at_once(self, fob): lso = LocalSourcesWatcher.LocalSourcesWatcher(REPORT, NOOP_CALLBACK) fob.assert_called_once() sys.modules["DUMMY_MODULE_1"] = DUMMY_MODULE_1 sys.modules["DUMMY_MODULE_2"] = DUMMY_MODULE_2 fob.reset_mock() lso.update_watched_modules() self.assertEqual(fob.call_count, 3) # dummy modules and __init__.py method_type = type(self.test_just_script) call_args_list = sort_args_list(fob.call_args_list) args = call_args_list[0].args self.assertTrue("__init__.py" in args[0]) args = call_args_list[1].args self.assertEqual(args[0], DUMMY_MODULE_1_FILE) self.assertEqual(type(args[1]), method_type) args = call_args_list[2].args self.assertEqual(args[0], DUMMY_MODULE_2_FILE) self.assertEqual(type(args[1]), method_type) fob.reset_mock() lso.update_watched_modules() self.assertEqual(fob.call_count, 0)
def test_auto_blacklist(self, _): prev_blacklist = config.get_option("server.folderWatchBlacklist") config.set_option("server.folderWatchBlacklist", []) lso = LocalSourcesWatcher.LocalSourcesWatcher(REPORT, NOOP_CALLBACK) def is_blacklisted(filepath): return any( _file_is_in_folder(filepath, blacklisted_folder) for blacklisted_folder in lso._folder_blacklist ) # miniconda, anaconda, and .*/ folders should be blacklisted self.assertTrue(is_blacklisted("/foo/miniconda2/script.py")) self.assertTrue(is_blacklisted("/foo/miniconda3/script.py")) self.assertTrue(is_blacklisted("/foo/anaconda2/script.py")) self.assertTrue(is_blacklisted("/foo/anaconda3/script.py")) self.assertTrue(is_blacklisted("/foo/.virtualenv/script.py")) self.assertTrue(is_blacklisted("/foo/.venv/script.py")) self.assertTrue(is_blacklisted("/foo/.random_hidden_folder/script.py")) # Ensure we're not accidentally blacklisting things we shouldn't be self.assertFalse(is_blacklisted("/foo/not_blacklisted/script.py")) self.assertFalse(is_blacklisted("/foo/not_blacklisted/.hidden_script.py")) # Reset the config object. config.set_option("server.folderWatchBlacklist", prev_blacklist)
def test_script_and_2_modules_in_series(self, fob): lso = LocalSourcesWatcher.LocalSourcesWatcher(REPORT, CALLBACK) fob.assert_called_once() sys.modules['DUMMY_MODULE_1'] = DUMMY_MODULE_1 fob.reset_mock() lso.update_watched_modules() self.assertEqual(fob.call_count, 2) # dummy module and __init__.py method_type = type(self.test_just_script) call_args_list = sort_args_list(fob.call_args_list) args = call_args_list[0].args self.assertTrue('__init__.py' in args[0]) args = call_args_list[1].args self.assertEqual(args[0], DUMMY_MODULE_1_FILE) self.assertEqual(type(args[1]), method_type) sys.modules['DUMMY_MODULE_2'] = DUMMY_MODULE_2 fob.reset_mock() lso.update_watched_modules() args = fob.call_args.args self.assertEqual(args[0], DUMMY_MODULE_2_FILE) self.assertEqual(type(args[1]), method_type) fob.assert_called_once()
def test_misbehaved_module(self, fob): lso = LocalSourcesWatcher.LocalSourcesWatcher(REPORT, NOOP_CALLBACK) fob.assert_called_once() sys.modules["MISBEHAVED_MODULE"] = MISBEHAVED_MODULE.MisbehavedModule fob.reset_mock() lso.update_watched_modules() fob.assert_called_once() # Just __init__.py
def test_permission_error(self, fob, _): from streamlit import compatibility if compatibility.is_running_py3(): ErrorType = PermissionError else: ErrorType = OSError fob.side_effect = ErrorType("This error should be caught!") lso = LocalSourcesWatcher.LocalSourcesWatcher(REPORT, NOOP_CALLBACK)
def test_just_script(self, fob): lso = LocalSourcesWatcher.LocalSourcesWatcher(REPORT, NOOP_CALLBACK) fob.assert_called_once() args = fob.call_args.args self.assertEqual(args[0], REPORT_PATH) method_type = type(self.test_just_script) self.assertEqual(type(args[1]), method_type) fob.reset_mock() lso.update_watched_modules() lso.update_watched_modules() lso.update_watched_modules() lso.update_watched_modules() self.assertEqual(fob.call_count, 1) # __init__.py
def test_blacklist(self, fob): prev_blacklist = config.get_option('server.folderWatchBlacklist') config.set_option('server.folderWatchBlacklist', [os.path.dirname(DUMMY_MODULE_1.__file__)]) lso = LocalSourcesWatcher.LocalSourcesWatcher(REPORT, CALLBACK) fob.assert_called_once() sys.modules['DUMMY_MODULE_1'] = DUMMY_MODULE_1 fob.reset_mock() lso.update_watched_modules() fob.assert_not_called() # Reset the config object. config.set_option('server.folderWatchBlacklist', prev_blacklist)
def test_nested_module_parent_unloaded(self, fob, _): lso = LocalSourcesWatcher.LocalSourcesWatcher(REPORT, NOOP_CALLBACK) fob.assert_called_once() with patch( "sys.modules", { "DUMMY_MODULE_1": DUMMY_MODULE_1, "NESTED_MODULE_PARENT": NESTED_MODULE_PARENT, "NESTED_MODULE_CHILD": NESTED_MODULE_CHILD, }, ): lso.update_watched_modules() # Simulate a change to the child module lso.on_file_changed(NESTED_MODULE_CHILD_FILE) # Assert that both the parent and child are unloaded, ready for reload self.assertNotIn("NESTED_MODULE_CHILD", sys.modules) self.assertNotIn("NESTED_MODULE_PARENT", sys.modules)
def test_config_blacklist(self, fob, _): """Test server.folderWatchBlacklist""" prev_blacklist = config.get_option("server.folderWatchBlacklist") config.set_option( "server.folderWatchBlacklist", [os.path.dirname(DUMMY_MODULE_1.__file__)] ) lso = LocalSourcesWatcher.LocalSourcesWatcher(REPORT, NOOP_CALLBACK) fob.assert_called_once() sys.modules["DUMMY_MODULE_1"] = DUMMY_MODULE_1 fob.reset_mock() lso.update_watched_modules() fob.assert_not_called() # Reset the config object. config.set_option("server.folderWatchBlacklist", prev_blacklist)
def test_file_not_in_folder(self): ret = LocalSourcesWatcher._file_is_in_folder("/a/b/c/foo.py", "/d/e/f/") self.assertFalse(ret)
def test_rel_file_not_in_folder(self): ret = LocalSourcesWatcher._file_is_in_folder('foo.py', '/d/e/f/') self.assertFalse(ret)
def test_file_in_folder(self): ret = LocalSourcesWatcher._file_is_in_folder('/a/b/c/foo.py', '/a/b/c/') self.assertTrue(ret)
def test_rel_file_not_in_folder_glob(self): ret = LocalSourcesWatcher._file_is_in_folder("foo.py", "**/f") self.assertFalse(ret)
def test_file_in_folder_glob(self): ret = LocalSourcesWatcher._file_is_in_folder("/a/b/c/foo.py", "**/c") self.assertTrue(ret)
def test_permission_error(self, fob, _): fob.side_effect = PermissionError("This error should be caught!") lso = LocalSourcesWatcher.LocalSourcesWatcher(REPORT, NOOP_CALLBACK)