Skip to content

Commit 88e193e

Browse files
committed
Add InterpreterValidator
添加用于验证指定文件是否为有效的Python解释器的工具类;
1 parent 61dd88c commit 88e193e

1 file changed

Lines changed: 104 additions & 0 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import os
2+
import subprocess
3+
from pathlib import Path
4+
from typing import Union
5+
6+
7+
class InterpreterValidator:
8+
"""
9+
验证给定的可执行文件是否为有效的Python解释器,并获取该解释器相关信息
10+
"""
11+
12+
def __init__(self, path: Union[str, os.PathLike[str]]) -> None:
13+
"""
14+
:param path: 可执行文件路径
15+
"""
16+
17+
self._itp_path: Path = Path(path)
18+
self._itp_validated: bool = False
19+
self.validate_itp()
20+
21+
def validate_itp(self) -> bool:
22+
"""
23+
:return: 解释器是否有效
24+
"""
25+
26+
if (
27+
self._itp_path.exists() # 该路径存在
28+
and self._itp_path.is_file() # 为文件
29+
and self._itp_path.name.startswith("python") # 文件名以python起始
30+
):
31+
try:
32+
# 尝试将该文件作为Python解释器运行
33+
subprocess_args = [
34+
str(self._itp_path.resolve()),
35+
"-c",
36+
"import sys",
37+
]
38+
result = subprocess.run(
39+
args=subprocess_args,
40+
timeout=300,
41+
)
42+
if result.returncode == 0:
43+
self._itp_validated = True
44+
return True
45+
else:
46+
self._itp_validated = False
47+
return False
48+
except OSError:
49+
self._itp_validated = False
50+
return False
51+
else:
52+
self._itp_validated = False
53+
return False
54+
55+
def itp_info(self):
56+
"""
57+
返回解释器的相关信息 \n
58+
"""
59+
60+
# FIXME 完善此方法
61+
if self._itp_validated:
62+
pass
63+
64+
def module_installed(self, module: str) -> bool:
65+
"""
66+
验证该解释器环境中是否已安装某个模块 \n
67+
:param module: 模块名,要求为import语句中使用的名称
68+
:return: 未安装该模块或解释器无效时返回False
69+
"""
70+
71+
if self._itp_validated:
72+
subprocess_arg_list = [
73+
str(self._itp_path.resolve()),
74+
"-c",
75+
f"import {module}",
76+
]
77+
result = subprocess.run(
78+
args=subprocess_arg_list,
79+
stdout=subprocess.PIPE,
80+
stderr=subprocess.PIPE,
81+
timeout=300,
82+
)
83+
if result.returncode != 0 and b"ModuleNotFoundError" in result.stderr:
84+
return False
85+
else:
86+
return True
87+
else:
88+
return False
89+
90+
@classmethod
91+
def validate(cls, path: Union[str, os.PathLike[str]]) -> bool:
92+
"""
93+
验证path是否指向有效的Python解释器 \n
94+
:return: 是否有效
95+
"""
96+
97+
return InterpreterValidator(path).validate_itp()
98+
99+
100+
if __name__ == "__main__":
101+
# print(InterpreterValidator.validate("/usr/bin/python"))
102+
iv = InterpreterValidator("/usr/bin/python")
103+
print(iv.module_installed("PySide6"))
104+
print(iv.module_installed("black"))

0 commit comments

Comments
 (0)