Skip to content

Commit e829c0c

Browse files
committed
Register WinPython distribution: added "Edit with Spyder" to context menu entries
and added "unregistration" process
1 parent 99a4556 commit e829c0c

File tree

2 files changed

+101
-31
lines changed

2 files changed

+101
-31
lines changed

winpython/associate.py

Lines changed: 79 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,74 +22,92 @@
2222
from winpython.py3compat import winreg
2323
from winpython import utils
2424

25+
KEY_C = r"Software\Classes\%s"
26+
KEY_C0 = KEY_C % r"Python.%sFile\shell\%s"
27+
KEY_C1 = KEY_C0 + r"\command"
28+
KEY_I = KEY_C % r"Python.%sFile\DefaultIcon"
29+
KEY_D = KEY_C % r"Python.%sFile"
30+
EWI = "Edit with IDLE"
31+
EWS = "Edit with Spyder"
32+
33+
34+
def _get_shortcut_data(target, current=True):
35+
wpgroup = utils.create_winpython_start_menu_folder(current=current)
36+
wpdir = osp.join(target, os.pardir)
37+
data = []
38+
for name in os.listdir(wpdir):
39+
bname, ext = osp.splitext(name)
40+
if ext == '.exe':
41+
data.append( (osp.join(wpdir, name),
42+
bname,
43+
osp.join(wpgroup, bname)) )
44+
return data
45+
2546

2647
def register(target, current=True):
2748
"""Register a Python distribution in Windows registry"""
2849
root = winreg.HKEY_CURRENT_USER if current else winreg.HKEY_LOCAL_MACHINE
2950

3051
# Extensions
31-
winreg.SetValueEx(winreg.CreateKey(root, r"Software\Classes\.py"),
52+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C % ".py"),
3253
"", 0, winreg.REG_SZ, "Python.File")
33-
winreg.SetValueEx(winreg.CreateKey(root, r"Software\Classes\.pyw"),
54+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C % ".pyw"),
3455
"", 0, winreg.REG_SZ, "Python.NoConFile")
35-
winreg.SetValueEx(winreg.CreateKey(root, r"Software\Classes\.pyc"),
56+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C % ".pyc"),
3657
"", 0, winreg.REG_SZ, "Python.CompiledFile")
37-
winreg.SetValueEx(winreg.CreateKey(root, r"Software\Classes\.pyo"),
58+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C % ".pyo"),
3859
"", 0, winreg.REG_SZ, "Python.CompiledFile")
3960

4061
# MIME types
41-
winreg.SetValueEx(winreg.CreateKey(root, r"Software\Classes\.py"),
62+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C % ".py"),
4263
"Content Type", 0, winreg.REG_SZ, "text/plain")
43-
winreg.SetValueEx(winreg.CreateKey(root, r"Software\Classes\.pyw"),
64+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C % ".pyw"),
4465
"Content Type", 0, winreg.REG_SZ, "text/plain")
4566

4667
# Verbs
4768
python = osp.abspath(osp.join(target, 'python.exe'))
4869
pythonw = osp.abspath(osp.join(target, 'pythonw.exe'))
49-
pat = r"Software\Classes\Python.%sFile\shell\%s\command"
50-
winreg.SetValueEx(winreg.CreateKey(root, pat % ("", "open")),
70+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C1 % ("", "open")),
5171
"", 0, winreg.REG_SZ, '"%s" "%%1" %%*' % python)
52-
winreg.SetValueEx(winreg.CreateKey(root, pat % ("NoCon", "open")),
72+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C1 % ("NoCon", "open")),
5373
"", 0, winreg.REG_SZ, '"%s" "%%1" %%*' % pythonw)
54-
winreg.SetValueEx(winreg.CreateKey(root, pat % ("Compiled", "open")),
74+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C1 % ("Compiled", "open")),
5575
"", 0, winreg.REG_SZ, '"%s" "%%1" %%*' % python)
56-
ewi = "Edit with IDLE"
57-
winreg.SetValueEx(winreg.CreateKey(root, pat % ("", ewi)),
76+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C1 % ("", EWI)),
5877
"", 0, winreg.REG_SZ,
5978
'"%s" "%s\Lib\idlelib\idle.pyw" -n -e "%%1"'
6079
% (pythonw, target))
61-
winreg.SetValueEx(winreg.CreateKey(root, pat % ("NoCon", ewi)),
80+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C1 % ("NoCon", EWI)),
6281
"", 0, winreg.REG_SZ,
6382
'"%s" "%s\Lib\idlelib\idle.pyw" -n -e "%%1"'
6483
% (pythonw, target))
84+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C1 % ("", EWS)),
85+
"", 0, winreg.REG_SZ,
86+
'"%s" "%s\Scripts\spyder" "%%1"' % (pythonw, target))
87+
winreg.SetValueEx(winreg.CreateKey(root, KEY_C1 % ("NoCon", EWS)),
88+
"", 0, winreg.REG_SZ,
89+
'"%s" "%s\Scripts\spyder" "%%1"' % (pythonw, target))
6590

6691
# Icons
6792
dlls = osp.join(target, 'DLLs')
68-
pat2 = r"Software\Classes\Python.%sFile\DefaultIcon"
69-
winreg.SetValueEx(winreg.CreateKey(root, pat2 % ""),
93+
winreg.SetValueEx(winreg.CreateKey(root, KEY_I % ""),
7094
"", 0, winreg.REG_SZ, r'%s\py.ico' % dlls)
71-
winreg.SetValueEx(winreg.CreateKey(root, pat2 % "NoCon"),
95+
winreg.SetValueEx(winreg.CreateKey(root, KEY_I % "NoCon"),
7296
"", 0, winreg.REG_SZ, r'%s\py.ico' % dlls)
73-
winreg.SetValueEx(winreg.CreateKey(root, pat2 % "Compiled"),
97+
winreg.SetValueEx(winreg.CreateKey(root, KEY_I % "Compiled"),
7498
"", 0, winreg.REG_SZ, r'%s\pyc.ico' % dlls)
7599

76100
# Descriptions
77-
pat3 = r"Software\Classes\Python.%sFile"
78-
winreg.SetValueEx(winreg.CreateKey(root, pat3 % ""),
101+
winreg.SetValueEx(winreg.CreateKey(root, KEY_D % ""),
79102
"", 0, winreg.REG_SZ, "Python File")
80-
winreg.SetValueEx(winreg.CreateKey(root, pat3 % "NoCon"),
103+
winreg.SetValueEx(winreg.CreateKey(root, KEY_D % "NoCon"),
81104
"", 0, winreg.REG_SZ, "Python File (no console)")
82-
winreg.SetValueEx(winreg.CreateKey(root, pat3 % "Compiled"),
105+
winreg.SetValueEx(winreg.CreateKey(root, KEY_D % "Compiled"),
83106
"", 0, winreg.REG_SZ, "Compiled Python File")
84107

85108
# Create start menu entries for all WinPython launchers
86-
wpgroup = utils.create_winpython_start_menu_folder(current=current)
87-
wpdir = osp.join(target, os.pardir)
88-
for name in os.listdir(wpdir):
89-
bname, ext = osp.splitext(name)
90-
if ext == '.exe':
91-
utils.create_shortcut(osp.join(wpdir, name), bname,
92-
osp.join(wpgroup, bname))
109+
for path, desc, fname in _get_shortcut_data(target, current=current):
110+
utils.create_shortcut(path, desc, fname)
93111

94112
# Register the Python ActiveX Scripting client (requires pywin32)
95113
axscript = osp.join(target, 'Lib', 'site-packages', 'win32comext',
@@ -101,5 +119,38 @@ def register(target, current=True):
101119
file=sys.stderr)
102120

103121

122+
def unregister(target, current=True):
123+
"""Unregister a Python distribution in Windows registry"""
124+
# Registry entries
125+
root = winreg.HKEY_CURRENT_USER if current else winreg.HKEY_LOCAL_MACHINE
126+
for key in (
127+
# Icons
128+
KEY_I % "NoCon", KEY_I % "Compiled", KEY_I % "",
129+
# Edit with IDLE
130+
KEY_C1 % ("", EWI), KEY_C1 % ("NoCon", EWI),
131+
KEY_C0 % ("", EWI), KEY_C0 % ("NoCon", EWI),
132+
# Edit with Spyder
133+
KEY_C1 % ("", EWS), KEY_C1 % ("NoCon", EWS),
134+
KEY_C0 % ("", EWS), KEY_C0 % ("NoCon", EWS),
135+
# Verbs
136+
KEY_C1 % ("", "open"), KEY_C1 % ("NoCon", "open"),
137+
KEY_C1 % ("Compiled", "open"),
138+
# Descriptions
139+
KEY_D % "NoCon", KEY_D % "Compiled", KEY_D % "",
140+
# Parent key
141+
KEY_C,
142+
):
143+
try:
144+
winreg.DeleteKey(root, key)
145+
except WindowsError:
146+
rootkey = 'HKEY_CURRENT_USER' if current else 'HKEY_LOCAL_MACHINE'
147+
raise WindowsError(r'Unable to remove %s\%s' % (rootkey, key))
148+
149+
# Start menu shortcuts
150+
for path, desc, fname in _get_shortcut_data(target, current=current):
151+
os.remove(fname)
152+
153+
104154
if __name__ == '__main__':
105155
register(sys.prefix)
156+
unregister(sys.prefix)

winpython/controlpanel.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,10 @@ def setup_window(self):
461461
register_action = create_action(self, "Register distribution...",
462462
tip="Register file extensions, icons and context menu",
463463
triggered=self.register_distribution)
464-
add_actions(option_menu, (register_action,))
464+
unregister_action = create_action(self, "Unregister distribution...",
465+
tip="Unregister file extensions, icons and context menu",
466+
triggered=self.unregister_distribution)
467+
add_actions(option_menu, (register_action, unregister_action))
465468

466469
# View menu
467470
# view_menu = self.menuBar().addMenu("&View")
@@ -534,7 +537,7 @@ def register_distribution(self):
534537
"""Register distribution"""
535538
answer = QMessageBox.warning(self, "Register distribution",
536539
"This will associate file extensions, icons and "
537-
"Windows explorer's context menu entry ('Edit with IDLE') "
540+
"Windows explorer's context menu entries ('Edit with IDLE', ...) "
538541
"with selected Python distribution in Windows registry. "
539542
"<br>Shortcuts for all WinPython launchers will be installed "
540543
"in <i>WinPython</i> Start menu group (replacing existing "
@@ -550,7 +553,23 @@ def register_distribution(self):
550553
QMessageBox.Yes | QMessageBox.No)
551554
if answer == QMessageBox.Yes:
552555
associate.register(self.distribution.target)
553-
556+
557+
def unregister_distribution(self):
558+
"""Unregister distribution"""
559+
answer = QMessageBox.warning(self, "Unregister distribution",
560+
"This will remove file extensions associations, icons and "
561+
"Windows explorer's context menu entries ('Edit with IDLE', ...) "
562+
"with selected Python distribution in Windows registry. "
563+
"<br>Shortcuts for all WinPython launchers will be removed "
564+
"from <i>WinPython</i> Start menu group."
565+
"<br>If <i>pywin32</i> is installed (it should be on any "
566+
"WinPython distribution), the Python ActiveX Scripting client "
567+
"will also be unregistered."
568+
"<br><br>Do you want to continue?",
569+
QMessageBox.Yes | QMessageBox.No)
570+
if answer == QMessageBox.Yes:
571+
associate.unregister(self.distribution.target)
572+
554573
def distribution_changed(self, path):
555574
"""Distribution path has just changed"""
556575
for package in self.table.model.packages:

0 commit comments

Comments
 (0)