From 6000edb33f9bf9845cadf1a6d2e96e59ccb9e010 Mon Sep 17 00:00:00 2001 From: Daniel Biehl Date: Wed, 1 Nov 2023 23:41:49 +0100 Subject: [PATCH] refactor(vscode): detection and running of python from vscode --- bundled/tool/utils/check_robot_version.py | 5 + .../robotframework/diagnostics/library_doc.py | 2 +- packages/robot/src/robotcode/robot/utils.py | 8 +- vscode-client/languageclientsmanger.ts | 114 +++++++++++------- vscode-client/testcontrollermanager.ts | 10 ++ 5 files changed, 90 insertions(+), 49 deletions(-) diff --git a/bundled/tool/utils/check_robot_version.py b/bundled/tool/utils/check_robot_version.py index 6307ca25b..10618835a 100644 --- a/bundled/tool/utils/check_robot_version.py +++ b/bundled/tool/utils/check_robot_version.py @@ -21,6 +21,11 @@ def update_sys_path(path_to_add: str, strategy: str) -> None: os.fspath(pathlib.Path(__file__).parent.parent.parent / "libs"), os.getenv("LS_IMPORT_STRATEGY", "useBundled"), ) + try: + __import__("robot") + except ModuleNotFoundError: + print("Robot Framework not installed", file=sys.stderr) + sys.exit(1) from robotcode.robot.utils import get_robot_version diff --git a/packages/language_server/src/robotcode/language_server/robotframework/diagnostics/library_doc.py b/packages/language_server/src/robotcode/language_server/robotframework/diagnostics/library_doc.py index 054bd2cf5..dabe68206 100644 --- a/packages/language_server/src/robotcode/language_server/robotframework/diagnostics/library_doc.py +++ b/packages/language_server/src/robotcode/language_server/robotframework/diagnostics/library_doc.py @@ -1759,7 +1759,7 @@ def get_test_library( from robot.libdocpkg.datatypes import TypeDoc as RobotTypeDoc from robot.running.arguments.argumentspec import TypeInfo - def _yield_type_info(info: TypeInfo) -> TypeInfo: + def _yield_type_info(info: TypeInfo) -> Iterable[TypeInfo]: if not info.is_union: yield info for nested in info.nested: diff --git a/packages/robot/src/robotcode/robot/utils.py b/packages/robot/src/robotcode/robot/utils.py index f0df6cd13..cec891e52 100644 --- a/packages/robot/src/robotcode/robot/utils.py +++ b/packages/robot/src/robotcode/robot/utils.py @@ -2,13 +2,17 @@ from robotcode.core.utils.version import Version, create_version_from_str +import robot.version + _robot_version: Optional[Version] = None def get_robot_version() -> Version: global _robot_version if _robot_version is None: - import robot.version - _robot_version = create_version_from_str(robot.version.get_version()) return _robot_version + + +def get_robot_version_str() -> str: + return str(robot.version.get_version()) diff --git a/vscode-client/languageclientsmanger.ts b/vscode-client/languageclientsmanger.ts index 19a6af6a7..1e29c2145 100644 --- a/vscode-client/languageclientsmanger.ts +++ b/vscode-client/languageclientsmanger.ts @@ -86,14 +86,16 @@ interface DiscoverInfoResult { system_version?: string; [key: string]: string | undefined; } + export class LanguageClientsManager { private clientsMutex = new Mutex(); + private _pythonValidPythonAndRobotEnvMutex = new Mutex(); public readonly clients: Map = new Map(); public readonly outputChannels: Map = new Map(); private _disposables: vscode.Disposable; - private _pythonValidPythonAndRobotEnv = new WeakMap(); + public _pythonValidPythonAndRobotEnv = new WeakMap(); private _workspaceFolderDiscoverInfo = new WeakMap(); private readonly _onClientStateChangedEmitter = new vscode.EventEmitter(); @@ -236,64 +238,84 @@ export class LanguageClientsManager { }); } - private async getServerOptions(folder: vscode.WorkspaceFolder, mode: string): Promise { - const config = vscode.workspace.getConfiguration(CONFIG_SECTION, folder); - - const pythonCommand = this.pythonManager.getPythonCommand(folder); + public async isValidRobotEnvironmentInFolder( + folder: vscode.WorkspaceFolder, + showDialogs?: boolean, + ): Promise { + return await this._pythonValidPythonAndRobotEnvMutex.dispatch(() => { + if (this._pythonValidPythonAndRobotEnv.has(folder)) { + return this._pythonValidPythonAndRobotEnv.get(folder) ?? false; + } - const envOk = this._pythonValidPythonAndRobotEnv.get(folder); - if (envOk === false) return undefined; + const pythonCommand = this.pythonManager.getPythonCommand(folder); + if (!pythonCommand) { + this._pythonValidPythonAndRobotEnv.set(folder, false); + if (showDialogs) { + this.showErrorWithSelectPythonInterpreter( + `Can't find a valid python executable for workspace folder '${folder.name}'. ` + + "Check if python and the python extension is installed.", + folder, + ); + } - if (!pythonCommand) { - this._pythonValidPythonAndRobotEnv.set(folder, false); + return false; + } - this.showErrorWithSelectPythonInterpreter( - `Can't find a valid python executable for workspace folder '${folder.name}'. ` + - "Check if python and the python extension is installed.", - folder, - ); + if (!this.pythonManager.checkPythonVersion(pythonCommand)) { + this._pythonValidPythonAndRobotEnv.set(folder, false); + if (showDialogs) { + this.showErrorWithSelectPythonInterpreter( + `Invalid python version for workspace folder '${folder.name}'. Only python version >= 3.8 supported. ` + + "Please update to a newer python version or select a valid python environment.", + folder, + ); + } - return undefined; - } + return false; + } - if (!this.pythonManager.checkPythonVersion(pythonCommand)) { - this._pythonValidPythonAndRobotEnv.set(folder, false); + const robotCheck = this.pythonManager.checkRobotVersion(pythonCommand); + if (robotCheck === undefined) { + this._pythonValidPythonAndRobotEnv.set(folder, false); - this.showErrorWithSelectPythonInterpreter( - `Invalid python version for workspace folder '${folder.name}'. Only python version >= 3.8 supported. ` + - "Please update to a newer python version or select a valid python environment.", - folder, - ); + if (showDialogs) { + this.showErrorWithSelectPythonInterpreter( + `Robot Framework package not found in workspace folder '${folder.name}'. ` + + "Please install Robot Framework >= version 4.1 to the current python environment or select a valid python environment.", + folder, + ); + } - return undefined; - } + return false; + } - const robotCheck = this.pythonManager.checkRobotVersion(pythonCommand); - if (robotCheck === undefined) { - this._pythonValidPythonAndRobotEnv.set(folder, false); + if (robotCheck === false) { + this._pythonValidPythonAndRobotEnv.set(folder, false); - this.showErrorWithSelectPythonInterpreter( - `Robot Framework package not found in workspace folder '${folder.name}'. ` + - "Please install Robot Framework >= Version 4.0 to the current python environment or select a valid python environment.", - folder, - ); + if (showDialogs) { + this.showErrorWithSelectPythonInterpreter( + `Robot Framework version in workspace folder '${folder.name}' not supported. Only Robot Framework version >= 4.1 supported. ` + + "Please install or update to Robot Framework >= version 4.1 to the current python environment or select a valid python environment.", + folder, + ); + } - return undefined; - } + return false; + } - if (robotCheck === false) { - this._pythonValidPythonAndRobotEnv.set(folder, false); + this._pythonValidPythonAndRobotEnv.set(folder, true); + return true; + }); + } - this.showErrorWithSelectPythonInterpreter( - `Robot Framework version in workspace folder '${folder.name}' not supported. Only Robot Framework version >= 4.0.0 supported. ` + - "Please install or update Robot Framework >= Version 4.0 to the current python environment or select a valid python environment.", - folder, - ); + private async getServerOptions(folder: vscode.WorkspaceFolder, mode: string): Promise { + const config = vscode.workspace.getConfiguration(CONFIG_SECTION, folder); - return undefined; - } + const envOk = await this.isValidRobotEnvironmentInFolder(folder, true); + if (envOk === false) return undefined; - this._pythonValidPythonAndRobotEnv.set(folder, true); + const pythonCommand = this.pythonManager.getPythonCommand(folder); + if (!pythonCommand) return undefined; const robotCodeExtraArgs = config.get("languageServer.extraArgs", []); @@ -714,7 +736,7 @@ export class LanguageClientsManager { try { const folder = vscode.workspace.getWorkspaceFolder(editor.document.uri); if (folder) { - if (!this._workspaceFolderDiscoverInfo.has(folder)) { + if (!this._workspaceFolderDiscoverInfo.has(folder) && (await this.isValidRobotEnvironmentInFolder(folder))) { this._workspaceFolderDiscoverInfo.set( folder, (await this.pythonManager.executeRobotCode(folder, ["discover", "info"])) as DiscoverInfoResult, diff --git a/vscode-client/testcontrollermanager.ts b/vscode-client/testcontrollermanager.ts index f6626e519..0561e6365 100644 --- a/vscode-client/testcontrollermanager.ts +++ b/vscode-client/testcontrollermanager.ts @@ -307,6 +307,12 @@ export class TestControllerManager { folder: vscode.WorkspaceFolder, profiles?: string[], ): Promise { + if (!(await this.languageClientsManager.isValidRobotEnvironmentInFolder(folder))) { + return { + profiles: [], + messages: [], + } as RobotCodeProfilesResult; + } const config = vscode.workspace.getConfiguration(CONFIG_SECTION, folder); const paths = config.get("robot.paths", undefined); @@ -523,6 +529,10 @@ export class TestControllerManager { stdioData?: string, token?: vscode.CancellationToken, ): Promise { + if (!(await this.languageClientsManager.isValidRobotEnvironmentInFolder(folder))) { + return {}; + } + const config = vscode.workspace.getConfiguration(CONFIG_SECTION, folder); const profiles = config.get("profiles", []); const pythonPath = config.get("robot.pythonPath", []);