On Tue, Feb 16, 2016 at 2:30 AM, Ulli Horlacher <frams...@rus.uni-stuttgart.de> wrote: > > So far, I use: > > system('setx PATH "%PATH%;'+bindir+'"') > > The problem: In a new process (cmd.exe) PATH contains a lot of double > elements. As far as I have understood, Windows builds the PATH > environment variable from a system component and a user component. With > the setx command from above I have copied the system PATH into the user > PATH component.
setx broadcasts a WM_SETTINGCHANGE [1] message that notifies Explorer to reload its environment from the registry, so the user doesn't have to start a new session. It also decides whether to use REG_SZ or REG_EXPAND_SZ depending on the presence of mutliple "%" characters in the string. [1]: https://msdn.microsoft.com/en-us/library/ms725497 But as you note it's no good for extending an existing value, especially not for PATH or a value that references other "%variables%" that you want to remain unexpanded. To do this right, you have to at least use winreg to query the user's PATH value from the registry. But then you may as well replace setx completely. Here's a little something to get you started. import os import sys import types import ctypes user32 = ctypes.WinDLL('user32', use_last_error=True) try: import winreg except ImportError: import _winreg as winreg def extend_path(new_paths, persist=True): if isinstance(new_paths, getattr(types, 'StringTypes', str)): new_paths = [new_paths] new_paths = [os.path.abspath(p) for p in new_paths] paths = [p for p in os.environ.get('PATH', '').split(os.pathsep) if p] for p in new_paths: if p not in paths: paths.append(p) os.environ['PATH'] = os.pathsep.join(paths) if persist: _persist_path(new_paths) def _persist_path(new_paths): if sys.version_info[0] == 2: temp_paths = [] for p in new_paths: if isinstance(p, unicode): temp_paths.append(p) else: temp_paths.append(p.decode('mbcs')) new_paths = temp_paths with winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Environment', 0, winreg.KEY_QUERY_VALUE | winreg.KEY_SET_VALUE) as hkey: try: user_path, dtype = winreg.QueryValueEx(hkey, 'PATH') except WindowsError as e: ERROR_FILE_NOT_FOUND = 0x0002 if e.winerror != ERROR_FILE_NOT_FOUND: raise paths = [] else: if dtype in (winreg.REG_SZ, winreg.REG_EXPAND_SZ): paths = [p for p in user_path.split(os.pathsep) if p] else: paths = [] for p in new_paths: if p not in paths: paths.append(p) pathstr = os.pathsep.join(paths) if pathstr.count('%') < 2: dtype = winreg.REG_SZ else: dtype = winreg.REG_EXPAND_SZ winreg.SetValueEx(hkey, 'PATH', 0, dtype, pathstr) _broadcast_change(u'Environment') def _broadcast_change(lparam): HWND_BROADCAST = 0xFFFF WM_SETTINGCHANGE = 0x001A SMTO_ABORTIFHUNG = 0x0002 ERROR_TIMEOUT = 0x05B4 wparam = 0 if not user32.SendMessageTimeoutW( HWND_BROADCAST, WM_SETTINGCHANGE, wparam, ctypes.c_wchar_p(lparam), SMTO_ABORTIFHUNG, 1000, None): err = ctypes.get_last_error() if err != ERROR_TIMEOUT: raise ctypes.WinError(err) -- https://mail.python.org/mailman/listinfo/python-list