/
environ.py
187 lines (161 loc) · 6.73 KB
/
environ.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# -*- 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.plugins.variableexplorer.widgets.collectionseditor import (
CollectionsEditor)
from spyder.py3compat import PY2, iteritems, to_text_string, to_binary_string
from spyder.utils import icon_manager as 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<br><br>"
"<tt>{0}</tt>").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 <b>pywin32 was not found</b>.<br>"
"Please restart this Windows <i>session</i> "
"(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 <b>in Windows registry</b>. "
"Use it with precautions, at your own risks.<br>"
"<br>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 <i>Python(x,y) Home</i> 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()