Skip to content

Commit 562a73c

Browse files
committed
Refactor PyEnv
启用新版 `PyEnv`: 不再仅仅是一个数据类型,还包括获取版本、已安装包等功能; 从 `Constants` 移至 `Utilities` 中;
1 parent b257c35 commit 562a73c

5 files changed

Lines changed: 45 additions & 65 deletions

File tree

src/py2exe_gui/Constants/python_env_constants.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
# For details: https://github.com/muziing/Py2exe-GUI/blob/main/README.md#license
33

44
import enum
5-
import subprocess
6-
from typing import NamedTuple
75

86

97
@enum.unique
@@ -17,29 +15,3 @@ class PyEnvType(enum.IntFlag):
1715
poetry = enum.auto() # Poetry 环境 https://python-poetry.org/
1816
conda = enum.auto() # conda 环境 https://docs.conda.io/en/latest/
1917
unknown = enum.auto() # 未知
20-
21-
22-
class PyEnv(NamedTuple):
23-
"""
24-
Python 解释器(环境)数据类
25-
"""
26-
27-
type: PyEnvType
28-
executable_path: str
29-
30-
31-
def get_pyenv_version(pyenv: PyEnv) -> str:
32-
"""
33-
获取Python解释器的版本,以形如 "3.11.7" 的字符串形式返回 \n
34-
:param pyenv: Python环境
35-
:return: Version of the Python interpreter, such as "3.11.7".
36-
"""
37-
38-
cmd = [
39-
pyenv.executable_path,
40-
"-c",
41-
"import platform;print(platform.python_version(), end='')",
42-
]
43-
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
44-
version = str(result.stdout, encoding="utf-8")
45-
return version

src/py2exe_gui/Utilities/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33

44
from .open_qfile import QtFileOpen
55
from .platform_specifc_funcs import get_sys_python, open_dir_in_explorer
6+
from .python_env import PyEnv
Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,19 @@ def __init__(
2020
executable_path: Union[str, Path],
2121
type_: Optional[PyEnvType] = PyEnvType.unknown,
2222
):
23-
self.executable_path = Path(executable_path)
23+
self._executable_path = Path(executable_path)
24+
self.exe_path = str(executable_path)
25+
self.type = type_
2426

2527
if type_ is None:
2628
# type_ 为 None 表示特殊含义——待推断
27-
self.type_ = self.infer_type(self.executable_path)
29+
self.type_ = self.infer_type(self._executable_path)
2830

29-
self.pyversion = self.get_py_version(self.executable_path)
30-
self.installed_packages = self.get_installed_packages(self.executable_path)
31+
self.pyversion = self.get_py_version(self._executable_path)
32+
self.installed_packages = self.get_installed_packages(self._executable_path)
3133

32-
@classmethod
33-
def get_py_version(cls, executable_path: Union[str, Path]) -> str:
34+
@staticmethod
35+
def get_py_version(executable_path: Union[str, Path]) -> str:
3436
"""
3537
获取Python解释器的版本,以形如 "3.11.7" 的字符串形式返回 \n
3638
:return: Version of the Python interpreter, such as "3.11.7".
@@ -40,8 +42,8 @@ def get_py_version(cls, executable_path: Union[str, Path]) -> str:
4042
version = subprocess.getoutput(cmd, encoding="utf-8")
4143
return version
4244

43-
@classmethod
44-
def get_installed_packages(cls, executable_path: Union[str, Path]) -> list[dict]:
45+
@staticmethod
46+
def get_installed_packages(executable_path: Union[str, Path]) -> list[dict]:
4547
"""
4648
获取该 Python 环境中已安装的包信息 \n
4749
:param executable_path: Python 解释器可执行文件路径
@@ -56,14 +58,14 @@ def get_installed_packages(cls, executable_path: Union[str, Path]) -> list[dict]
5658
@classmethod
5759
def infer_type(cls, executable_path: Union[str, Path]) -> PyEnvType:
5860
"""
59-
推断 Python 环境类型,如 venv Poetry Conda 等
61+
推断 Python 环境类型,如 venv Poetry Conda 等 \n
6062
"""
6163

6264
pass
6365

6466
def pkg_installed(self, package_name: str) -> bool:
6567
"""
66-
检索某个包是否已安装
68+
检索某个包是否已安装 \n
6769
:param package_name: 待检索的包名
6870
:return: 是否已安装
6971
"""

src/py2exe_gui/Widgets/pyenv_combobox.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
# Licensed under the GPLv3 License: https://www.gnu.org/licenses/gpl-3.0.html
22
# For details: https://github.com/muziing/Py2exe-GUI/blob/main/README.md#license
33

4-
import platform
54
import sys
65
from typing import Optional
76

87
from PySide6.QtCore import QSize
98
from PySide6.QtGui import QIcon
109
from PySide6.QtWidgets import QComboBox, QWidget
1110

12-
from ..Constants import RUNTIME_INFO, PyEnv, PyEnvType, get_pyenv_version
13-
from ..Utilities import get_sys_python
11+
from ..Constants import RUNTIME_INFO, PyEnvType
12+
from ..Utilities import PyEnv, get_sys_python
1413

1514

1615
class PyEnvComboBox(QComboBox):
@@ -25,20 +24,15 @@ def __init__(self, parent: Optional[QWidget] = None):
2524

2625
if not RUNTIME_INFO.is_bundled:
2726
# 在非 PyInstaller 捆绑环境中,第一项为当前用于运行 Py2exe-GUI 的 Python 环境
28-
current_pyenv = PyEnv(PyEnvType.poetry, executable_path=sys.executable)
27+
current_pyenv = PyEnv(sys.executable, PyEnvType.poetry)
2928
self.addItem(*self.gen_item(current_pyenv))
29+
sys_pyenv = PyEnv(get_sys_python(), PyEnvType.system)
30+
self.addItem(*self.gen_item(sys_pyenv))
3031
else:
3132
# 若已由 PyInstaller 捆绑成冻结应用程序,则第一项为系统 Python 环境
32-
sys_pyenv = PyEnv(PyEnvType.system, executable_path=get_sys_python())
33+
sys_pyenv = PyEnv(get_sys_python(), PyEnvType.system)
3334
self.addItem(*self.gen_item(sys_pyenv))
3435

35-
# 测试项
36-
self.addItem(
37-
QIcon(":/Icons/Python_128px"),
38-
f"Python {platform.python_version()}",
39-
sys.executable,
40-
)
41-
4236
@classmethod
4337
def gen_item(cls, pyenv: PyEnv) -> tuple:
4438
"""
@@ -47,8 +41,8 @@ def gen_item(cls, pyenv: PyEnv) -> tuple:
4741
:return: (icon, text, data)
4842
"""
4943

50-
data = pyenv.executable_path
51-
version = get_pyenv_version(pyenv)
44+
data = pyenv
45+
version = pyenv.pyversion
5246

5347
if pyenv.type == PyEnvType.system:
5448
icon = QIcon(":/Icons/Python_128px")

src/py2exe_gui/__main__.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
from PySide6.QtGui import QCloseEvent
88
from PySide6.QtWidgets import QApplication
99

10-
from .Constants import PyInstOpt # noqa
11-
from .Core import Packaging, PackagingTask # noqa
10+
from .Constants import PyInstOpt
11+
from .Core import Packaging, PackagingTask
1212
from .Resources import COMPILED_RESOURCES # noqa
13-
from .Utilities import open_dir_in_explorer # noqa
14-
from .Widgets import MainWindow, SubProcessDlg # noqa
13+
from .Utilities import PyEnv, open_dir_in_explorer
14+
from .Widgets import MainWindow, SubProcessDlg
1515

1616

1717
class MainApp(MainWindow):
@@ -22,6 +22,7 @@ class MainApp(MainWindow):
2222
def __init__(self, *args, **kwargs) -> None:
2323
super().__init__(*args, **kwargs)
2424

25+
self.current_pyenv: PyEnv
2526
self.packaging_task = PackagingTask(self)
2627
self.packager = Packaging(self)
2728
self.subprocess_dlg = SubProcessDlg(self)
@@ -63,16 +64,24 @@ def _connect_pyenv_change(self):
6364
处理用户通过选择不同的 Python 解释器时的响应
6465
"""
6566

66-
self.packager.set_python_path(self.center_widget.pyenv_combobox.currentData())
67-
self.center_widget.pyenv_combobox.currentIndexChanged.connect(
68-
lambda: self.packager.set_python_path(
69-
self.center_widget.pyenv_combobox.currentData()
67+
@Slot()
68+
def on_pyenv_change() -> None:
69+
"""
70+
处理用户通过选择不同的 Python 解释器时的响应
71+
"""
72+
73+
self.current_pyenv = self.center_widget.pyenv_combobox.currentData()
74+
self.packager.set_python_path(self.current_pyenv.exe_path)
75+
self.center_widget.hidden_import_dlg.pkg_browser_dlg.load_pkg_list(
76+
self.current_pyenv.installed_packages
7077
)
71-
)
78+
79+
on_pyenv_change() # 显式调用一次,确保用户无任何操作时也能正确处理默认pyenv
80+
self.center_widget.pyenv_combobox.currentIndexChanged.connect(on_pyenv_change)
7281

7382
def _connect_run_pkg_btn_slot(self):
7483
@Slot()
75-
def run_packaging() -> None:
84+
def on_run_packaging_btn_clicked() -> None:
7685
"""
7786
“运行打包”按钮的槽函数 \n
7887
"""
@@ -81,11 +90,13 @@ def run_packaging() -> None:
8190
self.subprocess_dlg.show()
8291
self.packager.run_packaging_process()
8392

84-
self.center_widget.run_packaging_btn.clicked.connect(run_packaging)
93+
self.center_widget.run_packaging_btn.clicked.connect(
94+
on_run_packaging_btn_clicked
95+
)
8596

8697
def _connect_mul_btn_slot(self, subprocess_dlg):
8798
@Slot()
88-
def handle_multifunction() -> None:
99+
def on_multifunction_btn_clicked() -> None:
89100
"""
90101
处理子进程窗口多功能按钮点击信号的槽 \n
91102
"""
@@ -102,7 +113,7 @@ def handle_multifunction() -> None:
102113
self.subprocess_dlg.close()
103114

104115
# 连接信号与槽
105-
subprocess_dlg.multifunction_btn.clicked.connect(handle_multifunction)
116+
subprocess_dlg.multifunction_btn.clicked.connect(on_multifunction_btn_clicked)
106117

107118
def closeEvent(self, event: QCloseEvent) -> None:
108119
"""

0 commit comments

Comments
 (0)