将单个 python 可执行文件添加到多台计算机的 windows 系统路径?
Adding a single python executable to windows system PATH for multiple computers?
我已经创建了一个命令行程序,我想分发给一些工作人员。让他们都安装 python 解释器是不现实的。因此,我使用 PyInstaller 创建了一个 .exe 文件。然而,我开始意识到,大多数人甚至不知道如何导航到 .exe 所在的目录,以便调用它。 (到目前为止,我还没有弄清楚如何在单击时让程序进入 运行。)有没有办法让程序在 [=15] 时将其自身添加到用户系统路径中=] 第一次还是需要安装程序?谢谢!
常见的陷阱是读取 PATH
环境。使用 os.environ('PATH')
变量。那将是一个 大 错误,因为此变量包含混合在一起的用户和系统路径。这是 PATH
变量的特例。
你需要做的是从注册表(用户部分)获取PATH
环境变量,如果需要更新它,然后写回。
您可以使用 winreg
模块,修改用户 PATH
环境变量(如果该特定用户不存在则创建)
- 读取用户
PATH
变量
- 如果存在,标记路径(否则,路径列表默认为空)
- 计算当前模块的路径(使用
os.path.dirname(__file__)
)
- 检查是否已经在路径中,如果是,退出(我在这种情况下打印路径列表,以便您测试)
- create/update
PATH
用户环境。如有必要,使用更新的路径列表变量
代码:
import winreg,os
script_directory = os.path.dirname(__file__)
paths = []
key_type = winreg.REG_EXPAND_SZ # default if PATH doesn't exist
try:
keyQ = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Environment', 0, winreg.KEY_QUERY_VALUE)
path_old, key_type = winreg.QueryValueEx(keyQ, "PATH")
winreg.CloseKey(keyQ)
paths = path_old.split(os.pathsep)
except WindowsError:
pass
if script_directory in paths:
# already set, do nothing
print(paths)
else:
# add the new path
paths.append(script_directory)
# change registry
keyQ = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Environment', 0, winreg.KEY_WRITE)
winreg.SetValueEx(keyQ, 'PATH', 0, key_type, os.pathsep.join(paths))
winreg.CloseKey(keyQ)
请注意,用户必须 logoff/logon 才能使更改生效。另一种解决方案是在 PATH
变量上调用 setx
。系统调用,丑陋,但立即生效。
# change registry with immediate effect
import subprocess
subprocess.call(["setx","PATH",os.pathsep.join(paths)])
或者,感谢 eryksun,一些 python 代码将注册表更改传播到新进程。无需注销,无需丑陋 setx
,只需使用以下代码调用 broadcast_change('Environment')
:
import ctypes
user32 = ctypes.WinDLL('user32', use_last_error=True)
HWND_BROADCAST = 0xFFFF
WM_SETTINGCHANGE = 0x001A
SMTO_ABORTIFHUNG = 0x0002
ERROR_TIMEOUT = 0x05B4
def broadcast_change(lparam):
result = user32.SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE,
0, ctypes.c_wchar_p(lparam), SMTO_ABORTIFHUNG, 1000, None)
if not result:
err = ctypes.get_last_error()
if err != ERROR_TIMEOUT:
raise ctypes.WinError(err)
(看来我必须用最后一点重构我自己的一些代码 :))
环境。变量读取代码取自这里:
我已经创建了一个命令行程序,我想分发给一些工作人员。让他们都安装 python 解释器是不现实的。因此,我使用 PyInstaller 创建了一个 .exe 文件。然而,我开始意识到,大多数人甚至不知道如何导航到 .exe 所在的目录,以便调用它。 (到目前为止,我还没有弄清楚如何在单击时让程序进入 运行。)有没有办法让程序在 [=15] 时将其自身添加到用户系统路径中=] 第一次还是需要安装程序?谢谢!
常见的陷阱是读取 PATH
环境。使用 os.environ('PATH')
变量。那将是一个 大 错误,因为此变量包含混合在一起的用户和系统路径。这是 PATH
变量的特例。
你需要做的是从注册表(用户部分)获取PATH
环境变量,如果需要更新它,然后写回。
您可以使用 winreg
模块,修改用户 PATH
环境变量(如果该特定用户不存在则创建)
- 读取用户
PATH
变量 - 如果存在,标记路径(否则,路径列表默认为空)
- 计算当前模块的路径(使用
os.path.dirname(__file__)
) - 检查是否已经在路径中,如果是,退出(我在这种情况下打印路径列表,以便您测试)
- create/update
PATH
用户环境。如有必要,使用更新的路径列表变量
代码:
import winreg,os
script_directory = os.path.dirname(__file__)
paths = []
key_type = winreg.REG_EXPAND_SZ # default if PATH doesn't exist
try:
keyQ = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Environment', 0, winreg.KEY_QUERY_VALUE)
path_old, key_type = winreg.QueryValueEx(keyQ, "PATH")
winreg.CloseKey(keyQ)
paths = path_old.split(os.pathsep)
except WindowsError:
pass
if script_directory in paths:
# already set, do nothing
print(paths)
else:
# add the new path
paths.append(script_directory)
# change registry
keyQ = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Environment', 0, winreg.KEY_WRITE)
winreg.SetValueEx(keyQ, 'PATH', 0, key_type, os.pathsep.join(paths))
winreg.CloseKey(keyQ)
请注意,用户必须 logoff/logon 才能使更改生效。另一种解决方案是在 PATH
变量上调用 setx
。系统调用,丑陋,但立即生效。
# change registry with immediate effect
import subprocess
subprocess.call(["setx","PATH",os.pathsep.join(paths)])
或者,感谢 eryksun,一些 python 代码将注册表更改传播到新进程。无需注销,无需丑陋 setx
,只需使用以下代码调用 broadcast_change('Environment')
:
import ctypes
user32 = ctypes.WinDLL('user32', use_last_error=True)
HWND_BROADCAST = 0xFFFF
WM_SETTINGCHANGE = 0x001A
SMTO_ABORTIFHUNG = 0x0002
ERROR_TIMEOUT = 0x05B4
def broadcast_change(lparam):
result = user32.SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE,
0, ctypes.c_wchar_p(lparam), SMTO_ABORTIFHUNG, 1000, None)
if not result:
err = ctypes.get_last_error()
if err != ERROR_TIMEOUT:
raise ctypes.WinError(err)
(看来我必须用最后一点重构我自己的一些代码 :))
环境。变量读取代码取自这里: