# -*- coding: utf-8 -*- # # Copyright © Spyder Project Contributors # Licensed under the terms of the MIT License # (see spyder/__init__.py for details) """ Environment variable utilities. """ # Standard library imports import os # Third party imports from qtpy.QtWidgets import QDialog, QMessageBox # Local imports from spyder.config.base import _ from spyder.widgets.collectionseditor import CollectionsEditor from spyder.py3compat import PY2, iteritems, to_text_string, to_binary_string from spyder.utils.icon_manager import ima from spyder.utils.encoding import to_unicode_from_fs def envdict2listdict(envdict): """Dict --> Dict of lists""" sep = os.path.pathsep for key in envdict: if sep in envdict[key]: envdict[key] = [path.strip() for path in envdict[key].split(sep)] return envdict def listdict2envdict(listdict): """Dict of lists --> Dict""" for key in listdict: if isinstance(listdict[key], list): listdict[key] = os.path.pathsep.join(listdict[key]) return listdict def clean_env(env_vars): """ Remove non-ascii entries from a dictionary of environments variables. The values will be converted to strings or bytes (on Python 2). If an exception is raised, an empty string will be used. """ new_env_vars = env_vars.copy() for key, var in iteritems(env_vars): if PY2: # Try to convert vars first to utf-8. try: unicode_var = to_text_string(var) except UnicodeDecodeError: # If that fails, try to use the file system # encoding because one of our vars is our # PYTHONPATH, and that contains file system # directories try: unicode_var = to_unicode_from_fs(var) except Exception: # If that also fails, make the var empty # to be able to start Spyder. # See https://stackoverflow.com/q/44506900/438386 # for details. unicode_var = '' new_env_vars[key] = to_binary_string(unicode_var, encoding='utf-8') else: new_env_vars[key] = to_text_string(var) return new_env_vars class RemoteEnvDialog(CollectionsEditor): """Remote process environment variables dialog.""" def __init__(self, environ, parent=None): super(RemoteEnvDialog, self).__init__(parent) try: self.setup( envdict2listdict(environ), title=_("Environment variables"), readonly=True, icon=ima.icon('environ') ) except Exception as e: QMessageBox.warning( parent, _("Warning"), _("An error occurred while trying to show your " "environment variables. The error was

" "{0}").format(e), QMessageBox.Ok ) class EnvDialog(RemoteEnvDialog): """Environment variables Dialog""" def __init__(self, parent=None): RemoteEnvDialog.__init__(self, dict(os.environ), parent=parent) # For Windows only try: from spyder.py3compat import winreg def get_user_env(): """Return HKCU (current user) environment variables""" reg = dict() key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Environment") for index in range(0, winreg.QueryInfoKey(key)[1]): try: value = winreg.EnumValue(key, index) reg[value[0]] = value[1] except: break return envdict2listdict(reg) def set_user_env(reg, parent=None): """Set HKCU (current user) environment variables""" reg = listdict2envdict(reg) types = dict() key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Environment") for name in reg: try: _x, types[name] = winreg.QueryValueEx(key, name) except WindowsError: types[name] = winreg.REG_EXPAND_SZ key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Environment", 0, winreg.KEY_SET_VALUE) for name in reg: winreg.SetValueEx(key, name, 0, types[name], reg[name]) try: from win32gui import SendMessageTimeout from win32con import (HWND_BROADCAST, WM_SETTINGCHANGE, SMTO_ABORTIFHUNG) SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, "Environment", SMTO_ABORTIFHUNG, 5000) except Exception: QMessageBox.warning(parent, _("Warning"), _("Module pywin32 was not found.
" "Please restart this Windows session " "(not the computer) for changes to take effect.")) class WinUserEnvDialog(CollectionsEditor): """Windows User Environment Variables Editor""" def __init__(self, parent=None): super(WinUserEnvDialog, self).__init__(parent) self.setup(get_user_env(), title=r"HKEY_CURRENT_USER\Environment") if parent is None: parent = self QMessageBox.warning(parent, _("Warning"), _("If you accept changes, " "this will modify the current user environment " "variables directly in Windows registry. " "Use it with precautions, at your own risks.
" "
Note that for changes to take effect, you will " "need to restart the parent process of this applica" "tion (simply restart Spyder if you have executed it " "from a Windows shortcut, otherwise restart any " "application from which you may have executed it, " "like Python(x,y) Home for example)")) def accept(self): """Reimplement Qt method""" set_user_env(listdict2envdict(self.get_value()), parent=self) QDialog.accept(self) except Exception: pass def main(): """Run Windows environment variable editor""" from spyder.utils.qthelpers import qapplication app = qapplication() if os.name == 'nt': dialog = WinUserEnvDialog() else: dialog = EnvDialog() dialog.show() app.exec_() if __name__ == "__main__": main()