diff options
| author | Brian Knudson <bk@vector35.com> | 2023-03-23 16:26:46 -0400 |
|---|---|---|
| committer | Brian Knudson <bk@vector35.com> | 2023-03-23 16:26:46 -0400 |
| commit | e69fc3a37b2408492d2812684521fbacd8d7e5ff (patch) | |
| tree | 140b06ec75b9afd73eb359c00a7251bb95cfcdcb /python | |
| parent | be1b9ceef5881d153876bbf4e8392c021b865847 (diff) | |
plugins: Update scriptingprovider.py to use environment that sets PYTHONHOME when calling pip using bundled python on macos. This fixes installing package dependencies that use setuptools
Diffstat (limited to 'python')
| -rw-r--r-- | python/scriptingprovider.py | 41 |
1 files changed, 25 insertions, 16 deletions
diff --git a/python/scriptingprovider.py b/python/scriptingprovider.py index 7b915461..06ac9170 100644 --- a/python/scriptingprovider.py +++ b/python/scriptingprovider.py @@ -33,7 +33,7 @@ import traceback from ctypes.util import find_library from pathlib import Path -from typing import Generator, Optional, List, Tuple +from typing import Generator, Optional, List, Tuple, Dict from typing import Type as TypeHintType # Binary Ninja components @@ -1202,7 +1202,8 @@ class PythonScriptingProvider(ScriptingProvider): def _python_bin(self) -> Optional[str]: python_lib = settings.Settings().get_string("python.interpreter") python_bin_override = settings.Settings().get_string("python.binaryOverride") - python_bin, status = self._get_executable_for_libpython(python_lib, python_bin_override) + python_env = self._get_python_environemnt(using_bundled_python=not python_lib) + python_bin, status = self._get_executable_for_libpython(python_lib, python_bin_override, python_env=python_env) return python_bin def _load_module(self, ctx, _repo_path: bytes, _module: bytes, force: bool): @@ -1241,38 +1242,40 @@ class PythonScriptingProvider(ScriptingProvider): log_info(f"Ignored python UI plugin: {repo_path}/{module}") return False - def _run_args(self, args): + def _run_args(self, args, env: Optional[Dict]=None): si = None if sys.platform == "win32": si = subprocess.STARTUPINFO() si.dwFlags |= subprocess.STARTF_USESHOWWINDOW try: - return (True, subprocess.check_output(args, startupinfo=si, stderr=subprocess.STDOUT).decode("utf-8")) + return (True, subprocess.check_output(args, startupinfo=si, stderr=subprocess.STDOUT, env=env).decode("utf-8")) except subprocess.SubprocessError as se: return (False, str(se)) - def _pip_exists(self, python_bin: str) -> bool: - return self._run_args([python_bin, "-m", "pip", "--version"])[0] + def _pip_exists(self, python_bin: str, python_env: Optional[Dict]=None) -> bool: + return self._run_args([python_bin, "-m", "pip", "--version"], env=python_env)[0] def _satisfied_dependencies(self, python_bin: str) -> Generator[str, None, None]: if python_bin is None: return None - success, result = self._run_args([python_bin, "-m", "pip", "freeze"]) + python_lib = settings.Settings().get_string("python.interpreter") + python_env = self._get_python_environment(using_bundled_python=not python_lib) + success, result = self._run_args([python_bin, "-m", "pip", "freeze"], env=python_env) if not success: return None for line in result.splitlines(): yield line.split("==", 2)[0] - def _bin_version(self, python_bin: str): + def _bin_version(self, python_bin: str, python_env: Optional[Dict]=None): return self._run_args([ str(python_bin), "-c", "import sys; sys.stdout.write(f'{sys.version_info.major}.{sys.version_info.minor}')" - ])[1] + ], env=python_env)[1] - def _get_executable_for_libpython(self, python_lib: str, python_bin: str) -> Tuple[Optional[str], str]: + def _get_executable_for_libpython(self, python_lib: str, python_bin: str, python_env: Optional[Dict]=None) -> Tuple[Optional[str], str]: python_lib_version = f"{sys.version_info.major}.{sys.version_info.minor}" if python_bin is not None and python_bin != "": - python_bin_version = self._bin_version(python_bin) + python_bin_version = self._bin_version(python_bin, python_env=python_env) if python_lib_version != python_bin_version: return ( None, @@ -1329,12 +1332,17 @@ class PythonScriptingProvider(ScriptingProvider): python_bin = Path(binaryninja.get_install_directory()) / "plugins\\python\\python.exe" else: python_bin = Path(python_lib).parent / "python.exe" - python_bin_version = self._bin_version(python_bin) + python_bin_version = self._bin_version(python_bin, python_env=python_env) if python_bin_version != python_lib_version: return (None, f"Failed: Python version not equal {python_bin_version} and {python_lib_version}") return (python_bin, "Success") + def _get_python_environment(self, using_bundled_python: bool=False) -> Optional[Dict]: + if using_bundled_python and sys.platform == "darwin": + return {"PYTHONHOME": Path(binaryninja.get_install_directory()).parent / f"Resources/bundled-python3"} + return None + def _install_modules(self, ctx, _modules: bytes) -> bool: # This callback should not be called directly modules = _modules.decode("utf-8") @@ -1342,8 +1350,9 @@ class PythonScriptingProvider(ScriptingProvider): return True python_lib = settings.Settings().get_string("python.interpreter") python_bin_override = settings.Settings().get_string("python.binaryOverride") - python_bin, status = self._get_executable_for_libpython(python_lib, python_bin_override) - if python_bin is not None and not self._pip_exists(str(python_bin)): + python_env = self._get_python_environment(using_bundled_python=not python_lib) + python_bin, status = self._get_executable_for_libpython(python_lib, python_bin_override, python_env=python_env) + if python_bin is not None and not self._pip_exists(str(python_bin), python_env=python_env): log_error( f"Pip not installed for configured python: {python_bin}.\n" "Please install pip or switch python versions." @@ -1358,7 +1367,7 @@ class PythonScriptingProvider(ScriptingProvider): python_bin_version = subprocess.check_output([ python_bin, "-c", "import sys; sys.stdout.write(f'{sys.version_info.major}.{sys.version_info.minor}')" - ]).decode("utf-8") + ], env=python_env).decode("utf-8") python_lib_version = f"{sys.version_info.major}.{sys.version_info.minor}" if (python_bin_version != python_lib_version): log_error( @@ -1387,7 +1396,7 @@ class PythonScriptingProvider(ScriptingProvider): args.extend(["--target", str(site_package_dir)]) args.extend(list(filter(len, modules.split("\n")))) log_info(f"Running pip {args}") - status, result = self._run_args(args) + status, result = self._run_args(args, env=python_env) if status: importlib.invalidate_caches() else: |
