Update PyEnv

更新 `PyEnv` 模块:
极大丰富注释与文档;
初步实现 `infer_type()` 方法;
删除不必要的实例属性;
This commit is contained in:
muzing 2023-12-28 22:50:30 +08:00
parent 40e3941c86
commit bc035f955b

View File

@ -1,18 +1,28 @@
# Licensed under the GPLv3 License: https://www.gnu.org/licenses/gpl-3.0.html
# For details: https://github.com/muziing/Py2exe-GUI/blob/main/README.md#license
"""此模块主要包含 Python 解释器环境类 `PyEnv`
用于存储 Python 环境的相关信息如解释器可执行文件路径Python 版本已安装的包等
"""
import json
import subprocess
from pathlib import Path
from typing import Optional, Union
from ..Constants import PyEnvType
from ..Utilities import get_sys_python
class PyEnv:
"""
Python 解释器环境类存储某个 Python 解释器对应的环境中的各种信息
解释器可执行文件路径Python 版本已安装的包等 \n
"""Python 解释器环境类,存储某个 Python 解释器对应的环境中的各种信息,如
解释器可执行文件路径Python 版本已安装的包等
静态方法
`PyEnv.get_py_version()` 用于获取 Python 版本号返回 "3.11.7" 形式的字符串
`PyEnv.get_installed_packages()` 用于获取已安装的包返回一个包含包名和版本的列表
`PyEnv.infer_type()` 用于推断 Python 解释器类型返回 PyEnvType 枚举类的成员
"""
def __init__(
@ -20,21 +30,26 @@ class PyEnv:
executable_path: Union[str, Path],
type_: Optional[PyEnvType] = PyEnvType.unknown,
):
self._executable_path = Path(executable_path)
self.exe_path = str(executable_path)
self.type = type_
"""
:param executable_path: Python 可执行文件路径
:param type_: Python 解释器类型PyEnvType 枚举类的成员传入显式的 None 则会触发自动识别
"""
self.exe_path = str(Path(executable_path).absolute())
self.pyversion = self.get_py_version(self.exe_path)
self.installed_packages = self.get_installed_packages(self.exe_path)
if type_ is None:
# type_ 为 None 表示特殊含义——待推断
self.type_ = self.infer_type(self._executable_path)
self.pyversion = self.get_py_version(self._executable_path)
self.installed_packages = self.get_installed_packages(self._executable_path)
# type_ 为 None 表示特殊含义“待推断”
self.type = self.infer_type(self.exe_path)
else:
self.type = type_
@staticmethod
def get_py_version(executable_path: Union[str, Path]) -> str:
"""
获取Python解释器的版本以形如 "3.11.7" 的字符串形式返回 \n
"""获取Python解释器的版本以形如 "3.11.7" 的字符串形式返回
:param executable_path: Python 可执行文件路径
:return: Version of the Python interpreter, such as "3.11.7".
"""
@ -52,8 +67,8 @@ class PyEnv:
@staticmethod
def get_installed_packages(executable_path: Union[str, Path]) -> list[dict]:
"""
获取该 Python 环境中已安装的包信息 \n
"""获取该 Python 环境中已安装的包信息
:param executable_path: Python 解释器可执行文件路径
:return: 包列表形如 [{'name': 'aiohttp', 'version': '3.9.1'}, {'name': 'aiosignal', 'version': '1.3.1'}, ...]
"""
@ -87,26 +102,53 @@ class PyEnv:
return installed_packages
@classmethod
def infer_type(cls, executable_path: Union[str, Path]) -> PyEnvType:
"""
推断 Python 环境类型 venv Poetry Conda \n
@staticmethod
def infer_type(executable_path: Union[str, Path]) -> PyEnvType:
"""推断 Python 环境类型,如 system venv Poetry Conda 等
暂时仅通过解析解释器绝对路径字符串正则匹配来判断有待改进
:param executable_path: Python 可执行文件路径
:return: PyEnvType 枚举类的成员
"""
pass
# 确保路径为 POSIX 风格的绝对路径
exe_path = Path(executable_path).absolute().as_posix()
# # 使用正则表达式匹配来检测不同的环境类型
# regexes = [
# (r"^.*venv.*", PyEnvType.venv),
# (r"^.*pypoetry.*", PyEnvType.poetry),
# (r"^.*conda.*", PyEnvType.conda),
# (
# re.escape(f"{Path(get_sys_python()).absolute().as_posix()}"),
# PyEnvType.system
# )]
# for regex, env_type in regexes:
# match = re.search(regex, str(exe_path))
# if match:
# return env_type
# 简单的字符串 in 方法,效率应该远高于正则匹配
match_pair = [
("venv", PyEnvType.venv),
("pypoetry", PyEnvType.poetry),
("conda", PyEnvType.conda),
(f"{Path(get_sys_python()).absolute().as_posix()}", PyEnvType.system),
]
for patten, env_type in match_pair:
if patten in exe_path:
return env_type
# 如果没有匹配到,返回 unknown
return PyEnvType.unknown
def pkg_installed(self, package_name: str) -> bool:
"""
检查特定软件包是否已安装 \n
"""检查特定软件包是否已安装
:param package_name: 待检索的软件包名称
:return: 是否已安装
"""
return any(pkg["name"] == package_name for pkg in self.installed_packages)
if __name__ == "__main__":
test_env = PyEnv("/usr/bin/python")
print(test_env.pyversion)
# print(test_env.installed_packages)
print(test_env.pkg_installed("yaml"))