使用Python全局和永久地修改'PATH'环境变量

使用Python全局和永久地修改'PATH'环境变量,python,cross-platform,environment-variables,distutils,Python,Cross Platform,Environment Variables,Distutils,是否可以使用Python(distutils)以独立于平台的方式全局和永久地修改PATH环境变量 背景 我有一些应用程序(SernaXML编辑器的插件),现在我将为它制作一个安装程序,可能使用python distutils(setup.py)。安装后,setup.py需要修改PATH环境变量以将安装目录添加到其值中 要实现我想要的目标,一个可能的解决方案是将可执行文件复制到/usr/local/bin或其他地方,但对于MS Windows来说,复制执行文件的位置并不明显 有什么想法吗?据我所知

是否可以使用Python(distutils)以独立于平台的方式全局和永久地修改
PATH
环境变量

背景 我有一些应用程序(SernaXML编辑器的插件),现在我将为它制作一个安装程序,可能使用python distutils(setup.py)。安装后,
setup.py
需要修改PATH环境变量以将安装目录添加到其值中

要实现我想要的目标,一个可能的解决方案是将可执行文件复制到
/usr/local/bin
或其他地方,但对于MS Windows来说,复制执行文件的位置并不明显


有什么想法吗?

据我所知,distutils没有用于永久更改环境变量的跨平台实用程序。因此,您必须编写特定于平台的代码

在Windows中,环境变量存储在注册表中。这是一个示例代码,用于读取和设置其中的一些键。我只使用标准库(无需安装pywin32!)来实现这一点

import _winreg as winreg
import ctypes

ENV_HTTP_PROXY = u'http://87.254.212.121:8080'


class Registry(object):
    def __init__(self, key_location, key_path):
        self.reg_key = winreg.OpenKey(key_location, key_path, 0, winreg.KEY_ALL_ACCESS)

    def set_key(self, name, value):
        try:
            _, reg_type = winreg.QueryValueEx(self.reg_key, name)
        except WindowsError:
            # If the value does not exists yet, we (guess) use a string as the
            # reg_type
            reg_type = winreg.REG_SZ
        winreg.SetValueEx(self.reg_key, name, 0, reg_type, value)

    def delete_key(self, name):
        try:
            winreg.DeleteValue(self.reg_key, name)
        except WindowsError:
            # Ignores if the key value doesn't exists
            pass



class EnvironmentVariables(Registry):
    """
    Configures the HTTP_PROXY environment variable, it's used by the PIP proxy
    """

    def __init__(self):
        super(EnvironmentVariables, self).__init__(winreg.HKEY_LOCAL_MACHINE,
                                                   r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment')

    def on(self):
        self.set_key('HTTP_PROXY', ENV_HTTP_PROXY)
        self.refresh()

    def off(self):
        self.delete_key('HTTP_PROXY')
        self.refresh()

    def refresh(self):
        HWND_BROADCAST = 0xFFFF
        WM_SETTINGCHANGE = 0x1A

        SMTO_ABORTIFHUNG = 0x0002

        result = ctypes.c_long()
        SendMessageTimeoutW = ctypes.windll.user32.SendMessageTimeoutW
        SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, u'Environment', SMTO_ABORTIFHUNG, 5000, ctypes.byref(result));
这只是一个示例代码供您开始使用,它只实现设置和删除键

确保在更改注册表后始终调用刷新方法。这将告诉Windows某些内容已更改,并将刷新注册表设置

下面是我编写的完整应用程序的链接,它是Windows的代理切换器:

据我所知,distutils没有用于永久更改环境变量的跨平台实用程序。因此,您必须编写特定于平台的代码

在Windows中,环境变量存储在注册表中。这是一个示例代码,用于读取和设置其中的一些键。我只使用标准库(无需安装pywin32!)来实现这一点

import _winreg as winreg
import ctypes

ENV_HTTP_PROXY = u'http://87.254.212.121:8080'


class Registry(object):
    def __init__(self, key_location, key_path):
        self.reg_key = winreg.OpenKey(key_location, key_path, 0, winreg.KEY_ALL_ACCESS)

    def set_key(self, name, value):
        try:
            _, reg_type = winreg.QueryValueEx(self.reg_key, name)
        except WindowsError:
            # If the value does not exists yet, we (guess) use a string as the
            # reg_type
            reg_type = winreg.REG_SZ
        winreg.SetValueEx(self.reg_key, name, 0, reg_type, value)

    def delete_key(self, name):
        try:
            winreg.DeleteValue(self.reg_key, name)
        except WindowsError:
            # Ignores if the key value doesn't exists
            pass



class EnvironmentVariables(Registry):
    """
    Configures the HTTP_PROXY environment variable, it's used by the PIP proxy
    """

    def __init__(self):
        super(EnvironmentVariables, self).__init__(winreg.HKEY_LOCAL_MACHINE,
                                                   r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment')

    def on(self):
        self.set_key('HTTP_PROXY', ENV_HTTP_PROXY)
        self.refresh()

    def off(self):
        self.delete_key('HTTP_PROXY')
        self.refresh()

    def refresh(self):
        HWND_BROADCAST = 0xFFFF
        WM_SETTINGCHANGE = 0x1A

        SMTO_ABORTIFHUNG = 0x0002

        result = ctypes.c_long()
        SendMessageTimeoutW = ctypes.windll.user32.SendMessageTimeoutW
        SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, u'Environment', SMTO_ABORTIFHUNG, 5000, ctypes.byref(result));
这只是一个示例代码供您开始使用,它只实现设置和删除键

确保在更改注册表后始终调用刷新方法。这将告诉Windows某些内容已更改,并将刷新注册表设置

下面是我编写的完整应用程序的链接,它是Windows的代理切换器:
Distutils不设置环境变量。在Windows上,这意味着破坏注册表;在UNIX上,需要找到正确的shell配置文件(这不是一个小问题)并对其进行编辑,这在这种文化中是不可能做到的:人们被告知编辑他们的$PATH或使用程序的完整路径。

Distutils不设置环境变量。在Windows上,这意味着破坏注册表;在UNIX上,需要找到正确的shell配置文件(这不是小事)并对其进行编辑,这在这种文化中是不可能做到的:人们被告知编辑他们的$PATH或使用程序的完整路径。

这是一个非常好的答案,但也要注意,如果这是一次性环境修改,您也可以使用
子流程
使用shell命令进行更改。这将大大减少代码,代价是打开一个新流程。这里有一个指向您希望在Windows中使用的命令(
setx
)的链接:@GrandOpener注意,
setx
会将路径截断为1024个字符,这可能会损坏它。另一方面,塞萨尔的回答并没有引入(潜在的灾难性)缺陷。@NickBadger这是一个极好的观察,但我们必须选择我们的战斗。如果路径长度超过2047,则需要处理另外一组潜在的灾难性问题。任何需要对非常不寻常的输入具有鲁棒性的解决方案都需要在尝试将其写入某个地方之前验证输入。我认为,对任何从事类似工作的人来说,了解这两个选项都是很好的。这是一个非常好的答案,但也要注意,如果这是一次性环境修改,那么使用
subprocess
来使用shell命令进行更改也会很好。这将大大减少代码,代价是打开一个新流程。这里有一个指向您希望在Windows中使用的命令(
setx
)的链接:@GrandOpener注意,
setx
会将路径截断为1024个字符,这可能会损坏它。另一方面,塞萨尔的回答并没有引入(潜在的灾难性)缺陷。@NickBadger这是一个极好的观察,但我们必须选择我们的战斗。如果路径长度超过2047,则需要处理另外一组潜在的灾难性问题。任何需要对非常不寻常的输入具有鲁棒性的解决方案都需要在尝试将其写入某个地方之前验证输入。我认为这两种选择对任何从事类似工作的人都有好处。