Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
354ad86
Make extentions use user's keys, not all defaults
CoolCat467 Oct 3, 2021
b6d2782
📜🤖 Added by blurb_it.
blurb-it[bot] Oct 3, 2021
48e18d6
Fix config and dialog to use user config extentions
CoolCat467 Oct 4, 2021
d8a267c
Merge branch 'python:main' into patch-1
CoolCat467 Oct 4, 2021
e1e8cd9
Remove debug print I forgot
CoolCat467 Oct 6, 2021
e2a2528
Remove debug comment out lines
CoolCat467 Oct 6, 2021
8fe6ecd
Merge branch 'python:main' into patch-1
CoolCat467 Oct 7, 2021
539d63b
Merge branch 'python:main' into patch-1
CoolCat467 Oct 16, 2021
1dfacb9
Merge branch 'python:main' into patch-1
CoolCat467 Nov 11, 2021
4e2161b
Fix spelling
CoolCat467 Feb 1, 2022
b425b72
Revert previous change
CoolCat467 Feb 1, 2022
88d40e0
Merge branch 'python:main' into patch-1
CoolCat467 May 24, 2022
c835095
Merge branch 'main' into patch-1
CoolCat467 Aug 27, 2023
f0e856a
Add trailing newline
CoolCat467 Aug 27, 2023
54b6c54
Merge branch 'main' into patch-1
CoolCat467 Aug 27, 2023
73c984e
Merge branch 'python:main' into patch-1
CoolCat467 Nov 11, 2023
40d864b
Simplify and update from `idleuserextend`'s testing
CoolCat467 Nov 11, 2023
fc190e3
Revert always save changes
CoolCat467 Nov 11, 2023
a2eb4b6
Merge branch 'python:main' into patch-1
CoolCat467 Nov 14, 2023
dc46fb7
Revert unnecessary formatting changes
CoolCat467 Nov 17, 2023
59b6a25
Merge branch 'main' into patch-1
CoolCat467 Nov 17, 2023
016ce89
`user_list` -> `user`, as is no longer a list but a set.
CoolCat467 Nov 17, 2023
ba7218f
Merge branch 'main' into patch-1
CoolCat467 Jan 26, 2024
954d0b8
Merge branch 'main' into patch-1
CoolCat467 Mar 11, 2024
568cd80
Revert noted strictly format change
CoolCat467 Mar 12, 2024
0240959
Remove suppression for errors that will never happen
CoolCat467 Mar 12, 2024
c032cf8
Merge branch 'main' into patch-1
CoolCat467 Mar 12, 2024
2f47ecb
Add test for ZzDummy being loaded in extensions list
CoolCat467 Mar 12, 2024
3a9d1dd
Don't require enabled
CoolCat467 Mar 12, 2024
29961f3
Add tests for reading extension keys
CoolCat467 Mar 12, 2024
8336d96
Merge branch 'main' into patch-1
CoolCat467 Mar 29, 2024
350253f
Merge branch 'main' into patch-1
CoolCat467 Apr 6, 2024
d6c8947
Merge branch 'main' into patch-1
CoolCat467 May 7, 2024
e521eef
Merge branch 'main' into patch-1
CoolCat467 May 12, 2024
9e04329
Merge branch 'main' into patch-1
CoolCat467 Aug 16, 2024
c0aaf33
Merge branch 'main' into patch-1
CoolCat467 Oct 8, 2024
e142132
Merge branch 'main' into patch-1
CoolCat467 Nov 6, 2024
455e8df
Merge branch 'main' into patch-1
CoolCat467 Dec 23, 2024
344d555
Merge branch 'main' into patch-1
CoolCat467 Feb 24, 2025
d814f03
Merge branch 'main' into patch-1
CoolCat467 Apr 18, 2025
7d0f5ac
Merge branch 'main' into patch-1
CoolCat467 Aug 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 36 additions & 13 deletions Lib/idlelib/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from configparser import ConfigParser
import os
import sys
from collections import ChainMap

from tkinter.font import Font
import idlelib
Expand Down Expand Up @@ -192,7 +193,7 @@ def GetUserCfgDir(self):
except OSError:
pass
userDir = '~'
if userDir == "~": # still no path to home!
else: # still no path to home!
# traditionally IDLE has defaulted to os.getcwd(), is this adequate?
userDir = os.getcwd()
userDir = os.path.join(userDir, cfgDir)
Expand All @@ -208,7 +209,7 @@ def GetUserCfgDir(self):
except OSError:
pass
raise SystemExit
# TODO continue without userDIr instead of exit
# TODO continue without userDir instead of exit
return userDir

def GetOption(self, configType, section, option, default=None, type=None,
Expand Down Expand Up @@ -266,7 +267,7 @@ def GetSectionList(self, configSet, configType):
if configSet == 'user':
cfgParser = self.userCfg[configType]
elif configSet == 'default':
cfgParser=self.defaultCfg[configType]
cfgParser = self.defaultCfg[configType]
else:
raise InvalidConfigSet('Invalid configSet specified')
return cfgParser.sections()
Expand Down Expand Up @@ -402,7 +403,7 @@ def current_colors_and_keys(self, section):

@staticmethod
def default_keys():
if sys.platform[:3] == 'win':
if sys.platform.startswith('win'):
return 'IDLE Classic Windows'
elif sys.platform == 'darwin':
return 'IDLE Classic OSX'
Expand Down Expand Up @@ -440,7 +441,7 @@ def GetExtensions(self, active_only=True,
option = "enable_editor"
else:
option = "enable_shell"
if self.GetOption('extensions', extn,option,
if self.GetOption('extensions', extn, option,
default=True, type='bool',
warn_on_default=False):
activeExtns.append(extn)
Expand Down Expand Up @@ -478,8 +479,16 @@ def GetExtensionKeys(self, extensionName):
keysName = extensionName + '_cfgBindings'
activeKeys = self.GetCurrentKeySet()
extKeys = {}

values = [[]]
if self.defaultCfg['extensions'].has_section(keysName):
eventNames = self.defaultCfg['extensions'].GetOptionList(keysName)
values.append(self.defaultCfg['extensions'].GetOptionList(keysName))
if self.userCfg['extensions'].has_section(keysName):
values.append(self.userCfg['extensions'].GetOptionList(keysName))
values.reverse()
eventNames = ChainMap(*values)

if eventNames:
for eventName in eventNames:
event = '<<' + eventName + '>>'
binding = activeKeys[event]
Expand All @@ -495,8 +504,16 @@ def __GetRawExtensionKeys(self,extensionName):
"""
keysName = extensionName+'_cfgBindings'
extKeys = {}

values = [[]]
if self.defaultCfg['extensions'].has_section(keysName):
eventNames = self.defaultCfg['extensions'].GetOptionList(keysName)
values.append(self.defaultCfg['extensions'].GetOptionList(keysName))
if self.userCfg['extensions'].has_section(keysName):
values.append(self.userCfg['extensions'].GetOptionList(keysName))
values.reverse()
eventNames = ChainMap(*values)

if eventNames:
for eventName in eventNames:
binding = self.GetOption(
'extensions', keysName, eventName, default='').split()
Expand All @@ -514,14 +531,19 @@ def GetExtensionBindings(self, extensionName):
bindsName = extensionName + '_bindings'
extBinds = self.GetExtensionKeys(extensionName)
#add the non-configurable bindings
values = [[]]
if self.defaultCfg['extensions'].has_section(bindsName):
eventNames = self.defaultCfg['extensions'].GetOptionList(bindsName)
values.append(self.defaultCfg['extensions'].GetOptionList(bindsName))
if self.userCfg['extensions'].has_section(bindsName):
values.append(self.userCfg['extensions'].GetOptionList(bindsName))
values.reverse()
eventNames = ChainMap(*values)
if eventNames:
for eventName in eventNames:
binding = self.GetOption(
'extensions', bindsName, eventName, default='').split()
event = '<<' + eventName + '>>'
extBinds[event] = binding

return extBinds

def GetKeyBinding(self, keySetName, eventStr):
Expand Down Expand Up @@ -578,7 +600,7 @@ def IsCoreBinding(self, virtualEvent):
"""
return ('<<'+virtualEvent+'>>') in self.GetCoreKeys()

# TODO make keyBindins a file or class attribute used for test above
# TODO make keyBindings a file or class attribute used for test above
# and copied in function below.

former_extension_events = { # Those with user-configurable keys.
Expand Down Expand Up @@ -701,7 +723,7 @@ def GetExtraHelpSourceList(self, configSet):
cfgParser = self.defaultCfg['main']
else:
raise InvalidConfigSet('Invalid configSet specified')
options=cfgParser.GetOptionList('HelpFiles')
options = cfgParser.GetOptionList('HelpFiles')
for option in options:
value=cfgParser.Get('HelpFiles', option, default=';')
if value.find(';') == -1: #malformed config entry with no ';'
Expand All @@ -712,7 +734,7 @@ def GetExtraHelpSourceList(self, configSet):
menuItem=value[0].strip()
helpPath=value[1].strip()
if menuItem and helpPath: #neither are empty strings
helpSources.append( (menuItem,helpPath,option) )
helpSources.append( (menuItem, helpPath, option) )
helpSources.sort(key=lambda x: x[2])
return helpSources

Expand Down Expand Up @@ -755,7 +777,8 @@ def LoadCfgFiles(self):
"Load all configuration files."
for key in self.defaultCfg:
self.defaultCfg[key].Load()
self.userCfg[key].Load() #same keys
for key in self.userCfg:
self.userCfg[key].Load() #not nessicerally same keys, could be more

def SaveUserCfgFiles(self):
"Write all loaded user configuration files to disk."
Expand Down
45 changes: 27 additions & 18 deletions Lib/idlelib/configdialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -1971,7 +1971,11 @@ def load_extensions(self):
self.extensions[ext_name] = []

for ext_name in self.extensions:
opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
opt_list = self.ext_defaultCfg.GetOptionList(ext_name)
user_list = self.ext_userCfg.GetOptionList(ext_name)
opt_list.extend(user_list)
user_list = set(user_list)
opt_list = list(set(sorted(opt_list)))

# Bring 'enable' options to the beginning of the list.
enables = [opt_name for opt_name in opt_list
Expand All @@ -1981,8 +1985,12 @@ def load_extensions(self):
opt_list = enables + opt_list

for opt_name in opt_list:
def_str = self.ext_defaultCfg.Get(
ext_name, opt_name, raw=True)
if opt_name in user_list:
def_str = self.ext_userCfg.Get(
ext_name, opt_name, raw=True)
else:
def_str = self.ext_defaultCfg.Get(
ext_name, opt_name, raw=True)
try:
def_obj = {'True':True, 'False':False}[def_str]
opt_type = 'bool'
Expand All @@ -1994,9 +2002,14 @@ def load_extensions(self):
def_obj = def_str
opt_type = None
try:
value = self.ext_userCfg.Get(
ext_name, opt_name, type=opt_type, raw=True,
default=def_obj)
if opt_name in user_list:
value = self.ext_userCfg.Get(
ext_name, opt_name, type=opt_type, raw=True,
default=def_obj)
else:
value = self.ext_defaultCfg.Get(
ext_name, opt_name, type=opt_type, raw=True,
default=def_obj)
except ValueError: # Need this until .Get fixed.
value = def_obj # Bad values overwritten by entry.
var = StringVar(self)
Expand Down Expand Up @@ -2044,7 +2057,7 @@ def create_extension_frame(self, ext_name):
validatecommand=(self.is_int, '%P'), width=10
).grid(row=row, column=1, sticky=NSEW, padx=7)

else: # type == 'str'
else: # opt['type'] == 'str'
# Limit size to fit non-expanding space with larger font.
Entry(entry_area, textvariable=var, width=15
).grid(row=row, column=1, sticky=NSEW, padx=7)
Expand All @@ -2060,10 +2073,10 @@ def set_extension_value(self, section, opt):
default = opt['default']
value = opt['var'].get().strip() or default
opt['var'].set(value)
# if self.defaultCfg.has_section(section):
# Currently, always true; if not, indent to return.
if (value == default):
return self.ext_userCfg.RemoveOption(section, name)
# Default config does not necessarily have section.
if self.ext_defaultCfg.has_section(section):
if (value == default):
return self.ext_userCfg.RemoveOption(section, name)
# Set the option.
return self.ext_userCfg.SetOption(section, name, value)

Expand All @@ -2076,14 +2089,10 @@ def save_all_changed_extensions(self):
Methods:
set_extension_value
"""
has_changes = False
for ext_name in self.extensions:
options = self.extensions[ext_name]
for opt in options:
if self.set_extension_value(ext_name, opt):
has_changes = True
if has_changes:
self.ext_userCfg.Save()
for opt in self.extensions[ext_name]:
self.set_extension_value(ext_name, opt)
self.ext_userCfg.Save()


class HelpFrame(LabelFrame):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make idlelib.config.idleConf's functions GetExtensionKeys, __GetRawExtensionKeys, and GetKeyBinding look at user config files, allowing custom extensions to have key-binds defined in ~/.idlerc instead of in the default key-binds file.