def test_complete_from_context(rf_server_api, libspec_manager, tmpdir): from robotframework_ls.impl.completion_context import CompletionContext from robotframework_ls.impl.robot_workspace import RobotDocument from robotframework_ls.impl.robot_workspace import RobotWorkspace from robocorp_ls_core.watchdog_wrapper import create_observer api = rf_server_api text = """*** Task *** Some task Log Something console=True Lo""" doc = RobotDocument("", text) line, col = doc.get_last_line_col() workspace = RobotWorkspace( str(tmpdir), fs_observer=create_observer("dummy", []), libspec_manager=libspec_manager, ) completion_context = CompletionContext(doc, line, col, workspace=workspace) for completion in api._complete_from_completion_context(completion_context): if completion["label"] == "Log": break else: raise AssertionError('Did not find "Log" entry in completions.')
def _obtain_fs_observer(self) -> IFSObserver: """ The FSObserver is needed to keep the list of files updated in the Workspace (_VirtualFS). """ try: return self._observer except AttributeError: from robocorp_ls_core import watchdog_wrapper self._observer = watchdog_wrapper.create_observer("dummy", None) return self._observer
def test_watchdog_all(tmpdir): from robocorp_ls_core import watchdog_wrapper from robocorp_ls_core.watchdog_wrapper import PathInfo from robocorp_ls_core.unittest_tools.fixtures import wait_for_test_condition tmpdir.join("dir_not_rec").mkdir() tmpdir.join("dir_rec").mkdir() found = [] def on_change(filepath, *args): found.append(filepath) assert args == ("foo", "bar") notifier = watchdog_wrapper.create_notifier(on_change, timeout=0.1) observer = watchdog_wrapper.create_observer() watch = observer.notify_on_any_change( [ PathInfo(tmpdir.join("dir_not_rec"), False), PathInfo(tmpdir.join("dir_rec"), True), ], notifier.on_change, call_args=("foo", "bar"), ) try: tmpdir.join("dir_not_rec").join("mya.txt").write("foo") tmpdir.join("dir_not_rec").join("mya.libspec").write("foo") tmpdir.join("dir_rec").join("myb.txt").write("foo") tmpdir.join("dir_rec").join("myb.libspec").write("foo") def collect_basenames(): import os.path basenames = [os.path.basename(x) for x in found] return set(basenames) def check1(): expected = {"myb.txt", "mya.libspec", "myb.libspec", "mya.txt"} return collect_basenames().issuperset(expected) wait_for_test_condition( check1, msg=lambda: f"Basenames found: {collect_basenames()}") finally: watch.stop_tracking() notifier.dispose() observer.dispose()
def __init__(self, builtin_libspec_dir=None, user_libspec_dir=None): """ :param __internal_libspec_dir__: Only to be used in tests (to regenerate the builtins)! """ from robocorp_ls_core import watchdog_wrapper self._libspec_failures_cache: Dict[tuple, bool] = {} self._main_thread = threading.current_thread() watch_impl = os.environ.get("ROBOTFRAMEWORK_LS_WATCH_IMPL", "watchdog") if watch_impl not in ("watchdog", "fsnotify"): log.info( f"ROBOTFRAMEWORK_LS_WATCH_IMPL should be 'watchdog' or 'fsnotify'. Found: {watch_impl} (falling back to fsnotify)" ) # i.e.: the default is watchdog, so, if a different one is set, # presumably the default is not ok, so, fall back to watchdog. watch_impl = "fsnotify" self._observer = watchdog_wrapper.create_observer( watch_impl, (".py", ".libspec") ) self._file_changes_notifier = watchdog_wrapper.create_notifier( self._on_file_changed, timeout=0.5 ) self._libspec_dir = self.get_internal_libspec_dir() self._user_libspec_dir = user_libspec_dir or os.path.join( self._libspec_dir, "user" ) self._builtins_libspec_dir = ( builtin_libspec_dir or self.get_internal_builtins_libspec_dir(self._libspec_dir) ) log.debug("User libspec dir: %s", self._user_libspec_dir) log.debug("Builtins libspec dir: %s", self._builtins_libspec_dir) try: os.makedirs(self._user_libspec_dir) except: # Ignore exception if it's already created. pass try: os.makedirs(self._builtins_libspec_dir) except: # Ignore exception if it's already created. pass # Spec info found in the workspace self._workspace_folder_uri_to_folder_info = {} self._additional_pythonpath_folder_to_folder_info = {} # Spec info found in the pythonpath pythonpath_folder_to_folder_info = {} for path in sys.path: if path and os.path.isdir(path): pythonpath_folder_to_folder_info[path] = _FolderInfo( path, recursive=False ) self._pythonpath_folder_to_folder_info = pythonpath_folder_to_folder_info # Spec info found in internal dirs (autogenerated) self._internal_folder_to_folder_info = { self._user_libspec_dir: _FolderInfo( self._user_libspec_dir, recursive=False ), self._builtins_libspec_dir: _FolderInfo( self._builtins_libspec_dir, recursive=False ), } # Must be set from the outside world when needed. self.config = None log.debug("Generating builtin libraries.") self._gen_builtin_libraries() log.debug("Synchronizing internal caches.") self._synchronize() log.debug("Finished initializing LibspecManager.")
def test_watchdog_extensions(tmpdir): from robocorp_ls_core import watchdog_wrapper from robocorp_ls_core.watchdog_wrapper import PathInfo from robocorp_ls_core.unittest_tools.fixtures import wait_for_test_condition tmpdir.join("dir_not_rec").mkdir() tmpdir.join("dir_rec").mkdir() found = [] def on_change(filepath, *args): found.append(filepath) assert args == ("foo", "bar") notifier = watchdog_wrapper.create_notifier(on_change, timeout=0.1) observer = watchdog_wrapper.create_observer() watch = observer.notify_on_extensions_change( [ PathInfo(tmpdir.join("dir_not_rec"), False), PathInfo(tmpdir.join("dir_rec"), True), ], ["libspec"], notifier.on_change, call_args=("foo", "bar"), ) try: tmpdir.join("my.txt").write("foo") tmpdir.join("my.libspec").write("foo") tmpdir.join("dir_not_rec").join("mya.txt").write("foo") tmpdir.join("dir_not_rec").join("mya.libspec").write("foo") tmpdir.join("dir_rec").join("myb.txt").write("foo") tmpdir.join("dir_rec").join("myb.libspec").write("foo") def check1(): found_my_a = False found_my_b = False for filepath in found: if not filepath.endswith(".libspec"): raise AssertionError( "Expected only libspec files to be tracked.") if filepath.endswith("my.libspec"): raise AssertionError("Wrong folder tracked.") found_my_a = found_my_a or "mya.libspec" in filepath found_my_b = found_my_b or "myb.libspec" in filepath return found_my_a and found_my_b wait_for_test_condition( check1, msg=lambda: "Expected to find mya.libspec and myb.libspec. Found:\n%s" % ("\n".join(found), ), ) # not listened tmpdir.join("dir_not_rec").join("another").mkdir() tmpdir.join("dir_not_rec").join("another").join("myc.txt").write("foo") tmpdir.join("dir_not_rec").join("another").join("myc.libspec").write( "foo") # listened tmpdir.join("dir_rec").join("another").mkdir() tmpdir.join("dir_rec").join("another").join("myd.txt").write("foo") tmpdir.join("dir_rec").join("another").join("myd.libspec").write("foo") del found[:] def check2(): found_my_d = False for filepath in found: if not filepath.endswith(".libspec"): raise AssertionError( "Expected only libspec files to be tracked.") if filepath.endswith("myc.libspec"): raise AssertionError("Wrong folder tracked.") found_my_d = found_my_d or "myd.libspec" in filepath return found_my_d wait_for_test_condition( check2, msg=lambda: "Expected to find myd.libspec. Found:\n%s" % ("\n".join(found), ), ) watch.stop_tracking() del found[:] tmpdir.join("dir_rec").join("mye.txt").write("foo") tmpdir.join("dir_rec").join("mye.libspec").write("foo") # Give time to check if some change arrives. time.sleep(1) assert not found finally: notifier.dispose() observer.dispose()
def __init__(self, builtin_libspec_dir=None, user_libspec_dir=None): """ :param __internal_libspec_dir__: Only to be used in tests (to regenerate the builtins)! """ from robocorp_ls_core import watchdog_wrapper self._libspec_failures_cache: Dict[tuple, bool] = {} self._main_thread = threading.current_thread() self._observer = watchdog_wrapper.create_observer() self._file_changes_notifier = watchdog_wrapper.create_notifier( self._on_file_changed, timeout=0.5) self._root_uri = None self._libspec_dir = self.get_internal_libspec_dir() self._user_libspec_dir = user_libspec_dir or os.path.join( self._libspec_dir, "user") self._builtins_libspec_dir = ( builtin_libspec_dir or self.get_internal_builtins_libspec_dir(self._libspec_dir)) log.debug("User libspec dir: %s", self._user_libspec_dir) log.debug("Builtins libspec dir: %s", self._builtins_libspec_dir) try: os.makedirs(self._user_libspec_dir) except BaseException: # Ignore exception if it's already created. pass try: os.makedirs(self._builtins_libspec_dir) except BaseException: # Ignore exception if it's already created. pass self.libspec_errors: Dict[LibspecErrorEntry, str] = {} self.libspec_warnings: Dict[LibspecErrorEntry, str] = {} # Spec info found in the workspace self._workspace_folder_uri_to_folder_info = {} self._additional_pythonpath_folder_to_folder_info = {} # Spec info found in the pythonpath pythonpath_folder_to_folder_info = {} for path in sys.path: if path and os.path.isdir(path): pythonpath_folder_to_folder_info[path] = _FolderInfo( path, recursive=False) self._pythonpath_folder_to_folder_info = pythonpath_folder_to_folder_info # Spec info found in internal dirs (autogenerated) self._internal_folder_to_folder_info = { self._user_libspec_dir: _FolderInfo(self._user_libspec_dir, recursive=False), self._builtins_libspec_dir: _FolderInfo(self._builtins_libspec_dir, recursive=False), } # Must be set from the outside world when needed. self.config = None self.process_pool = ProcessPoolExecutor() # we have to submit a dummy process to start the process pool, # because it does not start correctly if we do it from another # thread self.process_pool.submit(dummy_process).result() self.thread_pool = ThreadPoolExecutor( thread_name_prefix="libspec_manager_") log.debug("Generating builtin libraries.") self._gen_builtin_libraries() log.debug("Synchronizing internal caches.") self._synchronize() log.debug("Finished initializing LibspecManager.")
def test_workspace_memory_cache(tmpdir, small_vs_sleep): from robocorp_ls_core.workspace import Workspace from robocorp_ls_core import uris from robocorp_ls_core.lsp import WorkspaceFolder import os from typing import List from robocorp_ls_core.protocols import IWorkspaceFolder import typing from robocorp_ls_core.workspace import _WorkspaceFolderWithVirtualFS from robocorp_ls_core import watchdog_wrapper from robocorp_ls_core.basic import wait_for_condition root_uri = uris.from_fs_path(str(tmpdir)) workspace_folders: List[IWorkspaceFolder] = [ WorkspaceFolder(root_uri, os.path.basename(str(tmpdir))) ] fs_observer = watchdog_wrapper.create_observer("watchdog", extensions=(".py", ".txt")) ws = Workspace(root_uri, fs_observer, workspace_folders, track_file_extensions=(".py", ".txt")) folders = list(ws.iter_folders()) assert len(folders) == 1 folder = typing.cast(_WorkspaceFolderWithVirtualFS, folders[0]) vs = folder._vs wait_for_condition( lambda: list(ws.iter_all_doc_uris_in_workspace((".py", ".txt"))) == []) # If the change is too fast the mtime may end up being the same... f = tmpdir.join("my.txt") f.write_text("foo", "utf-8") wait_for_condition( lambda: list(ws.iter_all_doc_uris_in_workspace( (".py", ".txt"))) == [uris.from_fs_path(str(f))]) dir1 = tmpdir.join("dir1") dir1.mkdir() f2 = dir1.join("my.py") f2.write_text("foo", "utf-8") wait_for_condition( lambda: set(ws.iter_all_doc_uris_in_workspace((".py", ".txt"))) == {uris.from_fs_path(str(f)), uris.from_fs_path(str(f2))}) wait_for_condition( lambda: set(ws.iter_all_doc_uris_in_workspace((".py", ".txt"))) == {uris.from_fs_path(str(f)), uris.from_fs_path(str(f2))}) # If the change is too fast the mtime may end up being the same... f2.remove() wait_for_condition( lambda: set(ws.iter_all_doc_uris_in_workspace( (".py", ".txt"))) == {uris.from_fs_path(str(f))}) wait_for_condition( lambda: set(ws.iter_all_doc_uris_in_workspace( (".py", ".txt"))) == {uris.from_fs_path(str(f))}) ws.remove_folder(root_uri) assert set(ws.iter_all_doc_uris_in_workspace((".py", ".txt"))) == set() vs._virtual_fsthread.join(0.5) assert not vs._virtual_fsthread.is_alive()
def __init__(self, builtin_libspec_dir=None, user_libspec_dir=None): """ :param __internal_libspec_dir__: Only to be used in tests (to regenerate the builtins)! """ from robocorp_ls_core import watchdog_wrapper self._main_thread = threading.current_thread() self._observer = watchdog_wrapper.create_observer() self._spec_changes_notifier = watchdog_wrapper.create_notifier( self._on_spec_file_changed, timeout=0.5) self._libspec_dir = self.get_internal_libspec_dir() self._user_libspec_dir = user_libspec_dir or os.path.join( self._libspec_dir, "user") self._builtins_libspec_dir = ( builtin_libspec_dir or self.get_internal_builtins_libspec_dir(self._libspec_dir)) log.debug("User libspec dir: %s", self._user_libspec_dir) log.debug("Builtins libspec dir: %s", self._builtins_libspec_dir) try: os.makedirs(self._user_libspec_dir) except: # Ignore exception if it's already created. pass try: os.makedirs(self._builtins_libspec_dir) except: # Ignore exception if it's already created. pass # Spec info found in the workspace self._workspace_folder_uri_to_folder_info = {} self._additional_pythonpath_folder_to_folder_info = {} # Spec info found in the pythonpath pythonpath_folder_to_folder_info = {} for path in sys.path: if path and os.path.isdir(path): pythonpath_folder_to_folder_info[path] = _FolderInfo( path, recursive=False) self._pythonpath_folder_to_folder_info = pythonpath_folder_to_folder_info # Spec info found in internal dirs (autogenerated) self._internal_folder_to_folder_info = { self._user_libspec_dir: _FolderInfo(self._user_libspec_dir, recursive=False), self._builtins_libspec_dir: _FolderInfo(self._builtins_libspec_dir, recursive=False), } # Must be set from the outside world when needed. self.config = None log.debug("Generating builtin libraries.") self._gen_builtin_libraries() log.debug("Synchronizing internal caches.") self._synchronize() log.debug("Finished initializing LibspecManager.")
def __init__(self, builtin_libspec_dir=None, user_libspec_dir=None): """ :param __internal_libspec_dir__: Only to be used in tests (to regenerate the builtins)! """ from robocorp_ls_core import watchdog_wrapper self._libspec_failures_cache: Dict[tuple, bool] = {} self._main_thread = threading.current_thread() watch_impl = os.environ.get("ROBOTFRAMEWORK_LS_WATCH_IMPL", "auto") if watch_impl not in ("watchdog", "fsnotify", "auto"): log.info( f"ROBOTFRAMEWORK_LS_WATCH_IMPL should be 'auto', 'watchdog' or 'fsnotify'. Found: {watch_impl} (falling back to auto)" ) watch_impl = "auto" if watch_impl == "auto": # In auto mode we use watchdog for windows and fsnotify (polling) # for Linux and Mac. The reason for that is that on Linux and Mac # if big folders are watched the system may complain due to the # lack of resources, which may prevent the extension from working # properly. # # If users want to opt-in, they can change to watchdog (and # ideally install it to their env to get native extensions). if sys.platform == "win32": watch_impl = "watchdog" else: watch_impl = "fsnotify" self._observer = watchdog_wrapper.create_observer( watch_impl, (".py", ".libspec") ) self._file_changes_notifier = watchdog_wrapper.create_notifier( self._on_file_changed, timeout=0.5 ) self._libspec_dir = self.get_internal_libspec_dir() self._user_libspec_dir = user_libspec_dir or os.path.join( self._libspec_dir, "user" ) self._builtins_libspec_dir = ( builtin_libspec_dir or self.get_internal_builtins_libspec_dir(self._libspec_dir) ) log.debug("User libspec dir: %s", self._user_libspec_dir) log.debug("Builtins libspec dir: %s", self._builtins_libspec_dir) try: os.makedirs(self._user_libspec_dir) except: # Ignore exception if it's already created. pass try: os.makedirs(self._builtins_libspec_dir) except: # Ignore exception if it's already created. pass # Spec info found in the workspace self._workspace_folder_uri_to_folder_info = {} self._additional_pythonpath_folder_to_folder_info = {} # Spec info found in the pythonpath pythonpath_folder_to_folder_info = {} for path in sys.path: if path and os.path.isdir(path): pythonpath_folder_to_folder_info[path] = _FolderInfo( path, recursive=False ) self._pythonpath_folder_to_folder_info = pythonpath_folder_to_folder_info # Spec info found in internal dirs (autogenerated) self._internal_folder_to_folder_info = { self._user_libspec_dir: _FolderInfo( self._user_libspec_dir, recursive=False ), self._builtins_libspec_dir: _FolderInfo( self._builtins_libspec_dir, recursive=False ), } # Must be set from the outside world when needed. self.config = None log.debug("Generating builtin libraries.") self._gen_builtin_libraries() log.debug("Synchronizing internal caches.") self._synchronize() log.debug("Finished initializing LibspecManager.")