From 93e7797996891cc76065f2de23f108636b0a9122 Mon Sep 17 00:00:00 2001 From: krassowski <5832902+krassowski@users.noreply.github.com> Date: Mon, 20 Nov 2023 00:21:54 +0000 Subject: [PATCH 1/3] Resolve traitlets type warnings, lint, remove `six` --- atest/diagnostics.py | 42 +++++++++---------- atest/mouse_over_extension.py | 19 +++++---- .../jupyter_lsp/jupyter_lsp/manager.py | 20 +++++---- .../jupyter_lsp/tests/test_paths.py | 1 - .../jupyter_lsp/tests/test_stdio.py | 4 +- .../jupyter_lsp/jupyter_lsp/trait_types.py | 3 +- .../jupyter_lsp/jupyter_lsp/types.py | 8 ++-- .../jupyter_lsp/virtual_documents_shadow.py | 1 - requirements/dev.txt | 1 - requirements/lint.yml | 1 - 10 files changed, 52 insertions(+), 48 deletions(-) diff --git a/atest/diagnostics.py b/atest/diagnostics.py index 85224491d..d0e0c97bc 100644 --- a/atest/diagnostics.py +++ b/atest/diagnostics.py @@ -1,59 +1,59 @@ from functools import partial + from robot.libraries.BuiltIn import BuiltIn +from robot.utils import timestr_to_secs from selenium.common.exceptions import NoSuchElementException, TimeoutException -from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.remote.webdriver import WebDriver +from selenium.webdriver.support.wait import WebDriverWait from SeleniumLibrary import SeleniumLibrary -from robot.utils import timestr_to_secs +DIAGNOSTIC_CLASS = "cm-lintRange" -DIAGNOSTIC_CLASS = 'cm-lintRange' def page_contains_diagnostic(driver: WebDriver, selector, negate=False): - elements = driver.find_elements(By.CSS_SELECTOR, f'.{DIAGNOSTIC_CLASS}') + elements = driver.find_elements(By.CSS_SELECTOR, f".{DIAGNOSTIC_CLASS}") if not elements: return True if negate else False - driver.execute_script(""" + driver.execute_script( + """ arguments[0].map(el => { let diagnostic = el.cmView.mark.spec.diagnostic; el.title = diagnostic.message + " (" + diagnostic.source + ")"; }); - """, elements) + """, + elements, + ) try: - driver.find_element(By.CSS_SELECTOR, f'.{DIAGNOSTIC_CLASS}{selector}') + driver.find_element(By.CSS_SELECTOR, f".{DIAGNOSTIC_CLASS}{selector}") except NoSuchElementException: return True if negate else False return False if negate else True -def wait_until_page_contains_diagnostic(selector, timeout='5s'): +def wait_until_page_contains_diagnostic(selector, timeout="5s"): sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") wait = WebDriverWait(sl.driver, timestr_to_secs(timeout)) try: - return wait.until( - partial(page_contains_diagnostic, selector=selector) - ) + return wait.until(partial(page_contains_diagnostic, selector=selector)) except TimeoutException: - elements = sl.driver.find_elements(By.CSS_SELECTOR, f'.{DIAGNOSTIC_CLASS}') + elements = sl.driver.find_elements(By.CSS_SELECTOR, f".{DIAGNOSTIC_CLASS}") if elements: - titles = ( - '\n - ' - + '\n - '.join([el.get_attribute('title') for el in elements]) + titles = "\n - " + "\n - ".join( + [el.get_attribute("title") for el in elements] ) - hint = f'Visible diagnostics are: {titles}' + hint = f"Visible diagnostics are: {titles}" else: - hint = 'No diagnostics were visible.' + hint = "No diagnostics were visible." raise TimeoutException( - f'Diagnostic with selector {selector} not found in {timeout}.' - f'\n{hint}' + f"Diagnostic with selector {selector} not found in {timeout}." f"\n{hint}" ) -def wait_until_page_does_not_contain_diagnostic(selector, timeout='5s'): +def wait_until_page_does_not_contain_diagnostic(selector, timeout="5s"): sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") wait = WebDriverWait(sl.driver, timestr_to_secs(timeout)) return wait.until( partial(page_contains_diagnostic, selector=selector, negate=True), - f'Diagnostic with selector {selector} still present after {timeout}' + f"Diagnostic with selector {selector} still present after {timeout}", ) diff --git a/atest/mouse_over_extension.py b/atest/mouse_over_extension.py index 0c18125be..dcd8a63b1 100644 --- a/atest/mouse_over_extension.py +++ b/atest/mouse_over_extension.py @@ -17,7 +17,7 @@ def mouse_over_token_with_control(token_locator, x_wiggle=0): action.key_action.key_down(Keys.CONTROL) - action.pointer_action.move_to_location(location['x'], location['y']) + action.pointer_action.move_to_location(location["x"], location["y"]) wiggle(action, x_wiggle) action.key_action.key_up(Keys.CONTROL) @@ -28,14 +28,14 @@ def mouse_over_token_and_wiggle(token_locator, x_wiggle=5): sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") action = ActionBuilder(sl.driver) location = _find_text_in_line(token_locator) - action.pointer_action.move_to_location(location['x'], location['y']) + action.pointer_action.move_to_location(location["x"], location["y"]) wiggle(action, x_wiggle) return action.perform() def _find_text_in_line(token_locator: str): - which, text = token_locator.split(':', maxsplit=1) - assert which == 'lastToken' + which, text = token_locator.split(":", maxsplit=1) + assert which == "lastToken" sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") sl.driver.execute_script( """ @@ -83,9 +83,10 @@ def _find_text_in_line(token_locator: str): y: (rect.top + rect.bottom) / 2 } """, - text + text, ) + def _emit_over_text_in_line(token_locator: str, event: str): sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") location = _find_text_in_line(token_locator) @@ -101,7 +102,7 @@ def _emit_over_text_in_line(token_locator: str, event: str): location.parentElement.dispatchEvent(e); """, location, - event + event, ) @@ -109,13 +110,13 @@ def mouse_over_token(token_locator: str): sl: SeleniumLibrary = BuiltIn().get_library_instance("SeleniumLibrary") action = ActionBuilder(sl.driver) location = _find_text_in_line(token_locator) - action.pointer_action.move_to_location(location['x'], location['y']) + action.pointer_action.move_to_location(location["x"], location["y"]) return action.perform() def click_token(token_locator: str): - return _emit_over_text_in_line(token_locator, event='click') + return _emit_over_text_in_line(token_locator, event="click") def open_context_menu_over_token(token_locator: str): - return _emit_over_text_in_line(token_locator, event='contextmenu') + return _emit_over_text_in_line(token_locator, event="contextmenu") diff --git a/python_packages/jupyter_lsp/jupyter_lsp/manager.py b/python_packages/jupyter_lsp/jupyter_lsp/manager.py index c847e8c4d..26c230136 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/manager.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/manager.py @@ -63,11 +63,11 @@ class LanguageServerManager(LanguageServerManagerAPI): autodetect: bool = Bool( # type:ignore[assignment] True, help=_("try to find known language servers in sys.prefix (and elsewhere)") - ).tag( - config=True - ) + ).tag(config=True) - sessions: Dict[Tuple[Text], LanguageServerSession] = Dict_( # type:ignore[assignment] + sessions: Dict[ + Tuple[Text], LanguageServerSession + ] = Dict_( # type:ignore[assignment] trait=Instance(LanguageServerSession), default_value={}, help="sessions keyed by language server name", @@ -86,9 +86,15 @@ class LanguageServerManager(LanguageServerManagerAPI): help="""Whether the manager has been initialized""", default_value=False ) - all_listeners = List_(trait=LoadableCallable).tag(config=True) - server_listeners = List_(trait=LoadableCallable).tag(config=True) - client_listeners = List_(trait=LoadableCallable).tag(config=True) + all_listeners = List_( # type:ignore[var-annotated] + trait=LoadableCallable # type:ignore[arg-type] + ).tag(config=True) + server_listeners = List_( # type:ignore[var-annotated] + trait=LoadableCallable # type:ignore[arg-type] + ).tag(config=True) + client_listeners = List_( # type:ignore[var-annotated] + trait=LoadableCallable # type:ignore[arg-type] + ).tag(config=True) @default("language_servers") def _default_language_servers(self): diff --git a/python_packages/jupyter_lsp/jupyter_lsp/tests/test_paths.py b/python_packages/jupyter_lsp/jupyter_lsp/tests/test_paths.py index 9455fd89f..3360da4e0 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/tests/test_paths.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/tests/test_paths.py @@ -42,7 +42,6 @@ def test_normalize_posix_path_home_subdir( ], ) def test_normalize_windows_path_case(root_dir, expected_root_uri): # pragma: no cover - try: normalized = normalized_uri(root_dir) except FileNotFoundError as err: diff --git a/python_packages/jupyter_lsp/jupyter_lsp/tests/test_stdio.py b/python_packages/jupyter_lsp/jupyter_lsp/tests/test_stdio.py index 01dd285d0..74dcc0163 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/tests/test_stdio.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/tests/test_stdio.py @@ -43,7 +43,9 @@ def spawn_writer( ) ) return subprocess.Popen( - [sys.executable, "-u", str(commands_file)], stdout=subprocess.PIPE, bufsize=0 + [sys.executable, "-u", str(commands_file)], + stdout=subprocess.PIPE, + bufsize=0, ) diff --git a/python_packages/jupyter_lsp/jupyter_lsp/trait_types.py b/python_packages/jupyter_lsp/jupyter_lsp/trait_types.py index 5d6e76d63..858f8b9de 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/trait_types.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/trait_types.py @@ -1,4 +1,3 @@ -import six import traitlets @@ -34,7 +33,7 @@ def validate(self, obj, value): except Exception: self.error(obj, value) - if six.callable(value): + if callable(value): return value else: self.error(obj, value) diff --git a/python_packages/jupyter_lsp/jupyter_lsp/types.py b/python_packages/jupyter_lsp/jupyter_lsp/types.py index 3878935a3..756afb65c 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/types.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/types.py @@ -200,12 +200,12 @@ class LanguageServerManagerAPI(LoggingConfigurable, HasListeners): nodejs = Unicode(help=_("path to nodejs executable")).tag(config=True) - node_roots = List_([], help=_("absolute paths in which to seek node_modules")).tag( - config=True - ) + node_roots = List_( + Unicode(), help=_("absolute paths in which to seek node_modules") + ).tag(config=True) extra_node_roots = List_( - [], help=_("additional absolute paths to seek node_modules first") + Unicode(), help=_("additional absolute paths to seek node_modules first") ).tag(config=True) def find_node_module(self, *path_frag): diff --git a/python_packages/jupyter_lsp/jupyter_lsp/virtual_documents_shadow.py b/python_packages/jupyter_lsp/jupyter_lsp/virtual_documents_shadow.py index 8d389e512..abdf22ae5 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/virtual_documents_shadow.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/virtual_documents_shadow.py @@ -104,7 +104,6 @@ class ShadowFilesystemError(ValueError): def setup_shadow_filesystem(virtual_documents_uri: str): - if not virtual_documents_uri.startswith("file:/"): raise ShadowFilesystemError( # pragma: no cover 'Virtual documents URI has to start with "file:/", got ' diff --git a/requirements/dev.txt b/requirements/dev.txt index ad6f8e89b..5ffd3ddaf 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -7,4 +7,3 @@ pyls-isort pyls-mypy pytest-cov ruamel.yaml -types-six diff --git a/requirements/lint.yml b/requirements/lint.yml index f89b01cb8..93c856adf 100644 --- a/requirements/lint.yml +++ b/requirements/lint.yml @@ -12,4 +12,3 @@ dependencies: - pytest-tornasync - robotframework-robocop - robotframework-tidy - - types-six From 74d08d9bb216c9e7de7b2b58580b3d3d229e6ecd Mon Sep 17 00:00:00 2001 From: krassowski <5832902+krassowski@users.noreply.github.com> Date: Mon, 20 Nov 2023 01:23:54 +0000 Subject: [PATCH 2/3] Explicit default value --- python_packages/jupyter_lsp/jupyter_lsp/types.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python_packages/jupyter_lsp/jupyter_lsp/types.py b/python_packages/jupyter_lsp/jupyter_lsp/types.py index 756afb65c..281897bd2 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/types.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/types.py @@ -201,11 +201,15 @@ class LanguageServerManagerAPI(LoggingConfigurable, HasListeners): nodejs = Unicode(help=_("path to nodejs executable")).tag(config=True) node_roots = List_( - Unicode(), help=_("absolute paths in which to seek node_modules") + trait=Unicode(), + default_value=[], + help=_("absolute paths in which to seek node_modules"), ).tag(config=True) extra_node_roots = List_( - Unicode(), help=_("additional absolute paths to seek node_modules first") + trait=Unicode(), + default_value=[], + help=_("additional absolute paths to seek node_modules first"), ).tag(config=True) def find_node_module(self, *path_frag): From dadd9bb4a20749cff09d73509f46565567c21b2f Mon Sep 17 00:00:00 2001 From: krassowski <5832902+krassowski@users.noreply.github.com> Date: Sat, 25 Nov 2023 00:27:09 +0000 Subject: [PATCH 3/3] Use `traitlets.Any` because this is really a pathlib Path but we would need to pull https://github.com/Zsailer/traitlets_paths which was not updated in 5 years so it may not work --- python_packages/jupyter_lsp/jupyter_lsp/types.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python_packages/jupyter_lsp/jupyter_lsp/types.py b/python_packages/jupyter_lsp/jupyter_lsp/types.py index 281897bd2..021b6c783 100644 --- a/python_packages/jupyter_lsp/jupyter_lsp/types.py +++ b/python_packages/jupyter_lsp/jupyter_lsp/types.py @@ -28,6 +28,7 @@ except ImportError: # pragma: no cover from jupyter_server.transutils import _ +from traitlets import Any as Any_ from traitlets import Instance from traitlets import List as List_ from traitlets import Unicode, default @@ -201,13 +202,13 @@ class LanguageServerManagerAPI(LoggingConfigurable, HasListeners): nodejs = Unicode(help=_("path to nodejs executable")).tag(config=True) node_roots = List_( - trait=Unicode(), + trait=Any_(), default_value=[], help=_("absolute paths in which to seek node_modules"), ).tag(config=True) extra_node_roots = List_( - trait=Unicode(), + trait=Any_(), default_value=[], help=_("additional absolute paths to seek node_modules first"), ).tag(config=True)