Merge heads
This commit is contained in:
commit
763e04b442
|
@ -9,9 +9,9 @@ from email.utils import make_msgid
|
|||
# Create the base text message.
|
||||
msg = EmailMessage()
|
||||
msg['Subject'] = "Ayons asperges pour le déjeuner"
|
||||
msg['From'] = Address("Pepé Le Pew", "pepe@example.com")
|
||||
msg['To'] = (Address("Penelope Pussycat", "penelope@example.com"),
|
||||
Address("Fabrette Pussycat", "fabrette@example.com"))
|
||||
msg['From'] = Address("Pepé Le Pew", "pepe", "example.com")
|
||||
msg['To'] = (Address("Penelope Pussycat", "penelope", "example.com"),
|
||||
Address("Fabrette Pussycat", "fabrette", "example.com"))
|
||||
msg.set_content("""\
|
||||
Salut!
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ way we could process it:
|
|||
|
||||
Up to the prompt, the output from the above is::
|
||||
|
||||
To: Penelope Pussycat <"penelope@example.com">, Fabrette Pussycat <"fabrette@example.com">
|
||||
To: Penelope Pussycat <penelope@example.com>, Fabrette Pussycat <fabrette@example.com>
|
||||
From: Pepé Le Pew <pepe@example.com>
|
||||
Subject: Ayons asperges pour le déjeuner
|
||||
|
||||
|
|
|
@ -109,6 +109,57 @@ change-indentwidth=<Alt-Key-u>
|
|||
del-word-left=<Alt-Key-BackSpace>
|
||||
del-word-right=<Alt-Key-d>
|
||||
|
||||
[IDLE Modern Unix]
|
||||
copy = <Control-Shift-Key-C> <Control-Key-Insert>
|
||||
cut = <Control-Key-x> <Shift-Key-Delete>
|
||||
paste = <Control-Key-v> <Shift-Key-Insert>
|
||||
beginning-of-line = <Key-Home>
|
||||
center-insert = <Control-Key-l>
|
||||
close-all-windows = <Control-Key-q>
|
||||
close-window = <Control-Key-w> <Control-Shift-Key-W>
|
||||
do-nothing = <Control-Key-F12>
|
||||
end-of-file = <Control-Key-d>
|
||||
history-next = <Alt-Key-n> <Meta-Key-n>
|
||||
history-previous = <Alt-Key-p> <Meta-Key-p>
|
||||
interrupt-execution = <Control-Key-c>
|
||||
view-restart = <Key-F6>
|
||||
restart-shell = <Control-Key-F6>
|
||||
open-class-browser = <Control-Key-b>
|
||||
open-module = <Control-Key-m>
|
||||
open-new-window = <Control-Key-n>
|
||||
open-window-from-file = <Control-Key-o>
|
||||
plain-newline-and-indent = <Control-Key-j>
|
||||
print-window = <Control-Key-p>
|
||||
python-context-help = <Shift-Key-F1>
|
||||
python-docs = <Key-F1>
|
||||
redo = <Control-Shift-Key-Z>
|
||||
remove-selection = <Key-Escape>
|
||||
save-copy-of-window-as-file = <Alt-Shift-Key-S>
|
||||
save-window-as-file = <Control-Shift-Key-S>
|
||||
save-window = <Control-Key-s>
|
||||
select-all = <Control-Key-a>
|
||||
toggle-auto-coloring = <Control-Key-slash>
|
||||
undo = <Control-Key-z>
|
||||
find = <Control-Key-f>
|
||||
find-again = <Key-F3>
|
||||
find-in-files = <Control-Shift-Key-f>
|
||||
find-selection = <Control-Key-h>
|
||||
replace = <Control-Key-r>
|
||||
goto-line = <Control-Key-g>
|
||||
smart-backspace = <Key-BackSpace>
|
||||
newline-and-indent = <Key-Return> <Key-KP_Enter>
|
||||
smart-indent = <Key-Tab>
|
||||
indent-region = <Control-Key-bracketright>
|
||||
dedent-region = <Control-Key-bracketleft>
|
||||
comment-region = <Control-Key-d>
|
||||
uncomment-region = <Control-Shift-Key-D>
|
||||
tabify-region = <Alt-Key-5>
|
||||
untabify-region = <Alt-Key-6>
|
||||
toggle-tabs = <Control-Key-T>
|
||||
change-indentwidth = <Alt-Key-u>
|
||||
del-word-left = <Control-Key-BackSpace>
|
||||
del-word-right = <Control-Key-Delete>
|
||||
|
||||
[IDLE Classic Mac]
|
||||
copy=<Command-Key-c>
|
||||
cut=<Command-Key-x>
|
||||
|
|
|
@ -70,7 +70,9 @@ name2=
|
|||
|
||||
[Keys]
|
||||
default= 1
|
||||
name= IDLE Classic Windows
|
||||
name=
|
||||
name2=
|
||||
# name2 set in user config-main.cfg for keys added after 2016 July 1
|
||||
|
||||
[History]
|
||||
cyclic=1
|
||||
|
|
|
@ -234,10 +234,7 @@ class IdleConf:
|
|||
' from section %r: %r' %
|
||||
(type, option, section,
|
||||
self.userCfg[configType].Get(section, option, raw=raw)))
|
||||
try:
|
||||
print(warning, file=sys.stderr)
|
||||
except OSError:
|
||||
pass
|
||||
_warn(warning, configType, section, option)
|
||||
try:
|
||||
if self.defaultCfg[configType].has_option(section,option):
|
||||
return self.defaultCfg[configType].Get(
|
||||
|
@ -251,10 +248,7 @@ class IdleConf:
|
|||
' from section %r.\n'
|
||||
' returning default value: %r' %
|
||||
(option, section, default))
|
||||
try:
|
||||
print(warning, file=sys.stderr)
|
||||
except OSError:
|
||||
pass
|
||||
_warn(warning, configType, section, option)
|
||||
return default
|
||||
|
||||
def SetOption(self, configType, section, option, value):
|
||||
|
@ -362,47 +356,68 @@ class IdleConf:
|
|||
'\n from theme %r.\n'
|
||||
' returning default color: %r' %
|
||||
(element, themeName, theme[element]))
|
||||
try:
|
||||
print(warning, file=sys.stderr)
|
||||
except OSError:
|
||||
pass
|
||||
_warn(warning, 'highlight', themeName, element)
|
||||
theme[element] = cfgParser.Get(
|
||||
themeName, element, default=theme[element])
|
||||
return theme
|
||||
|
||||
def CurrentTheme(self):
|
||||
"""Return the name of the currently active text color theme.
|
||||
"Return the name of the currently active text color theme."
|
||||
return self.current_colors_and_keys('Theme')
|
||||
|
||||
def CurrentKeys(self):
|
||||
"""Return the name of the currently active key set."""
|
||||
return self.current_colors_and_keys('Keys')
|
||||
|
||||
def current_colors_and_keys(self, section):
|
||||
"""Return the currently active name for Theme or Keys section.
|
||||
|
||||
idlelib.config-main.def ('default') includes these sections
|
||||
|
||||
idlelib.config-main.def includes this section
|
||||
[Theme]
|
||||
default= 1
|
||||
name= IDLE Classic
|
||||
name2=
|
||||
# name2 set in user config-main.cfg for themes added after 2015 Oct 1
|
||||
|
||||
Item name2 is needed because setting name to a new builtin
|
||||
causes older IDLEs to display multiple error messages or quit.
|
||||
[Keys]
|
||||
default= 1
|
||||
name=
|
||||
name2=
|
||||
|
||||
Item 'name2', is used for built-in ('default') themes and keys
|
||||
added after 2015 Oct 1 and 2016 July 1. This kludge is needed
|
||||
because setting 'name' to a builtin not defined in older IDLEs
|
||||
to display multiple error messages or quit.
|
||||
See https://bugs.python.org/issue25313.
|
||||
When default = True, name2 takes precedence over name,
|
||||
while older IDLEs will just use name.
|
||||
When default = True, 'name2' takes precedence over 'name',
|
||||
while older IDLEs will just use name. When default = False,
|
||||
'name2' may still be set, but it is ignored.
|
||||
"""
|
||||
cfgname = 'highlight' if section == 'Theme' else 'keys'
|
||||
default = self.GetOption('main', 'Theme', 'default',
|
||||
type='bool', default=True)
|
||||
name = ''
|
||||
if default:
|
||||
theme = self.GetOption('main', 'Theme', 'name2', default='')
|
||||
if default and not theme or not default:
|
||||
theme = self.GetOption('main', 'Theme', 'name', default='')
|
||||
source = self.defaultCfg if default else self.userCfg
|
||||
if source['highlight'].has_section(theme):
|
||||
return theme
|
||||
name = self.GetOption('main', section, 'name2', default='')
|
||||
if not name:
|
||||
name = self.GetOption('main', section, 'name', default='')
|
||||
if name:
|
||||
source = self.defaultCfg if default else self.userCfg
|
||||
if source[cfgname].has_section(name):
|
||||
return name
|
||||
return "IDLE Classic" if section == 'Theme' else self.default_keys()
|
||||
|
||||
@staticmethod
|
||||
def default_keys():
|
||||
if sys.platform[:3] == 'win':
|
||||
return 'IDLE Classic Windows'
|
||||
elif sys.platform == 'darwin':
|
||||
return 'IDLE Classic OSX'
|
||||
else:
|
||||
return "IDLE Classic"
|
||||
return 'IDLE Modern Unix'
|
||||
|
||||
def CurrentKeys(self):
|
||||
"Return the name of the currently active key set."
|
||||
return self.GetOption('main', 'Keys', 'name', default='')
|
||||
|
||||
def GetExtensions(self, active_only=True, editor_only=False, shell_only=False):
|
||||
def GetExtensions(self, active_only=True,
|
||||
editor_only=False, shell_only=False):
|
||||
"""Return extensions in default and user config-extensions files.
|
||||
|
||||
If active_only True, only return active (enabled) extensions
|
||||
|
@ -422,7 +437,7 @@ class IdleConf:
|
|||
if self.GetOption('extensions', extn, 'enable', default=True,
|
||||
type='bool'):
|
||||
#the extension is enabled
|
||||
if editor_only or shell_only: # TODO if both, contradictory
|
||||
if editor_only or shell_only: # TODO both True contradict
|
||||
if editor_only:
|
||||
option = "enable_editor"
|
||||
else:
|
||||
|
@ -527,7 +542,8 @@ class IdleConf:
|
|||
eventStr - virtual event, including brackets, as in '<<event>>'.
|
||||
"""
|
||||
eventName = eventStr[2:-2] #trim off the angle brackets
|
||||
binding = self.GetOption('keys', keySetName, eventName, default='').split()
|
||||
binding = self.GetOption('keys', keySetName, eventName, default='',
|
||||
warn_on_default=False).split()
|
||||
return binding
|
||||
|
||||
def GetCurrentKeySet(self):
|
||||
|
@ -638,20 +654,28 @@ class IdleConf:
|
|||
'<<del-word-right>>': ['<Control-Key-Delete>']
|
||||
}
|
||||
if keySetName:
|
||||
for event in keyBindings:
|
||||
binding = self.GetKeyBinding(keySetName, event)
|
||||
if binding:
|
||||
keyBindings[event] = binding
|
||||
else: #we are going to return a default, print warning
|
||||
warning=('\n Warning: config.py - IdleConf.GetCoreKeys'
|
||||
' -\n problem retrieving key binding for event %r'
|
||||
'\n from key set %r.\n'
|
||||
' returning default value: %r' %
|
||||
(event, keySetName, keyBindings[event]))
|
||||
try:
|
||||
print(warning, file=sys.stderr)
|
||||
except OSError:
|
||||
pass
|
||||
if not (self.userCfg['keys'].has_section(keySetName) or
|
||||
self.defaultCfg['keys'].has_section(keySetName)):
|
||||
warning = (
|
||||
'\n Warning: config.py - IdleConf.GetCoreKeys -\n'
|
||||
' key set %r is not defined, using default bindings.' %
|
||||
(keySetName,)
|
||||
)
|
||||
_warn(warning, 'keys', keySetName)
|
||||
else:
|
||||
for event in keyBindings:
|
||||
binding = self.GetKeyBinding(keySetName, event)
|
||||
if binding:
|
||||
keyBindings[event] = binding
|
||||
else: #we are going to return a default, print warning
|
||||
warning = (
|
||||
'\n Warning: config.py - IdleConf.GetCoreKeys -\n'
|
||||
' problem retrieving key binding for event %r\n'
|
||||
' from key set %r.\n'
|
||||
' returning default value: %r' %
|
||||
(event, keySetName, keyBindings[event])
|
||||
)
|
||||
_warn(warning, 'keys', keySetName, event)
|
||||
return keyBindings
|
||||
|
||||
def GetExtraHelpSourceList(self, configSet):
|
||||
|
@ -735,6 +759,18 @@ class IdleConf:
|
|||
|
||||
idleConf = IdleConf()
|
||||
|
||||
|
||||
_warned = set()
|
||||
def _warn(msg, *key):
|
||||
key = (msg,) + key
|
||||
if key not in _warned:
|
||||
try:
|
||||
print(msg, file=sys.stderr)
|
||||
except OSError:
|
||||
pass
|
||||
_warned.add(key)
|
||||
|
||||
|
||||
# TODO Revise test output, write expanded unittest
|
||||
#
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -341,6 +341,7 @@ class ConfigDialog(Toplevel):
|
|||
buttonSaveCustomKeys = Button(
|
||||
frames[1], text='Save as New Custom Key Set',
|
||||
command=self.SaveAsNewKeySet)
|
||||
self.new_custom_keys = Label(frames[0], bd=2)
|
||||
|
||||
##widget packing
|
||||
#body
|
||||
|
@ -361,6 +362,7 @@ class ConfigDialog(Toplevel):
|
|||
self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS)
|
||||
self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW)
|
||||
self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW)
|
||||
self.new_custom_keys.grid(row=0, column=2, sticky=NSEW, padx=5, pady=5)
|
||||
self.buttonDeleteCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
|
||||
buttonSaveCustomKeys.pack(side=LEFT, fill=X, expand=True, padx=2)
|
||||
frames[0].pack(side=TOP, fill=BOTH, expand=True)
|
||||
|
@ -514,10 +516,11 @@ class ConfigDialog(Toplevel):
|
|||
self.OnNewColourSet()
|
||||
|
||||
def VarChanged_builtinTheme(self, *params):
|
||||
oldthemes = ('IDLE Classic', 'IDLE New')
|
||||
value = self.builtinTheme.get()
|
||||
if value == 'IDLE Dark':
|
||||
if idleConf.GetOption('main', 'Theme', 'name') != 'IDLE New':
|
||||
self.AddChangedItem('main', 'Theme', 'name', 'IDLE Classic')
|
||||
if value not in oldthemes:
|
||||
if idleConf.GetOption('main', 'Theme', 'name') not in oldthemes:
|
||||
self.AddChangedItem('main', 'Theme', 'name', oldthemes[0])
|
||||
self.AddChangedItem('main', 'Theme', 'name2', value)
|
||||
self.new_custom_theme.config(text='New theme, see Help',
|
||||
fg='#500000')
|
||||
|
@ -557,8 +560,23 @@ class ConfigDialog(Toplevel):
|
|||
self.AddChangedItem('extensions', extKeybindSection, event, value)
|
||||
|
||||
def VarChanged_builtinKeys(self, *params):
|
||||
oldkeys = (
|
||||
'IDLE Classic Windows',
|
||||
'IDLE Classic Unix',
|
||||
'IDLE Classic Mac',
|
||||
'IDLE Classic OSX',
|
||||
)
|
||||
value = self.builtinKeys.get()
|
||||
self.AddChangedItem('main', 'Keys', 'name', value)
|
||||
if value not in oldkeys:
|
||||
if idleConf.GetOption('main', 'Keys', 'name') not in oldkeys:
|
||||
self.AddChangedItem('main', 'Keys', 'name', oldkeys[0])
|
||||
self.AddChangedItem('main', 'Keys', 'name2', value)
|
||||
self.new_custom_keys.config(text='New key set, see Help',
|
||||
fg='#500000')
|
||||
else:
|
||||
self.AddChangedItem('main', 'Keys', 'name', value)
|
||||
self.AddChangedItem('main', 'Keys', 'name2', '')
|
||||
self.new_custom_keys.config(text='', fg='black')
|
||||
self.LoadKeysList(value)
|
||||
|
||||
def VarChanged_customKeys(self, *params):
|
||||
|
@ -767,8 +785,10 @@ class ConfigDialog(Toplevel):
|
|||
else:
|
||||
self.optMenuKeysCustom.SetMenu(itemList, itemList[0])
|
||||
#revert to default key set
|
||||
self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys', 'default'))
|
||||
self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name'))
|
||||
self.keysAreBuiltin.set(idleConf.defaultCfg['main']
|
||||
.Get('Keys', 'default'))
|
||||
self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys', 'name')
|
||||
or idleConf.default_keys())
|
||||
#user can't back out of these changes, they must be applied now
|
||||
self.SaveAllChangedConfigs()
|
||||
self.ActivateConfigChanges()
|
||||
|
@ -1067,7 +1087,7 @@ class ConfigDialog(Toplevel):
|
|||
self.optMenuKeysCustom.SetMenu(itemList, currentOption)
|
||||
itemList = idleConf.GetSectionList('default', 'keys')
|
||||
itemList.sort()
|
||||
self.optMenuKeysBuiltin.SetMenu(itemList, itemList[0])
|
||||
self.optMenuKeysBuiltin.SetMenu(itemList, idleConf.default_keys())
|
||||
self.SetKeysType()
|
||||
##load keyset element list
|
||||
keySetName = idleConf.CurrentKeys()
|
||||
|
@ -1369,12 +1389,18 @@ machine. Some do not take affect until IDLE is restarted.
|
|||
[Cancel] only cancels changes made since the last save.
|
||||
'''
|
||||
help_pages = {
|
||||
'Highlighting':'''
|
||||
'Highlighting': '''
|
||||
Highlighting:
|
||||
The IDLE Dark color theme is new in October 2015. It can only
|
||||
be used with older IDLE releases if it is saved as a custom
|
||||
theme, with a different name.
|
||||
'''
|
||||
''',
|
||||
'Keys': '''
|
||||
Keys:
|
||||
The IDLE Modern Unix key set is new in June 2016. It can only
|
||||
be used with older IDLE releases if it is saved as a custom
|
||||
key set, with a different name.
|
||||
''',
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
'''Test idlelib.config.
|
||||
|
||||
Much is tested by opening config dialog live or in test_configdialog.
|
||||
Coverage: 27%
|
||||
'''
|
||||
from sys import modules
|
||||
from test.support import captured_stderr
|
||||
from tkinter import Tk
|
||||
import unittest
|
||||
from idlelib import config
|
||||
|
||||
# Tests should not depend on fortuitous user configurations.
|
||||
# They must not affect actual user .cfg files.
|
||||
# Replace user parsers with empty parsers that cannot be saved.
|
||||
|
||||
idleConf = config.idleConf
|
||||
usercfg = idleConf.userCfg
|
||||
testcfg = {}
|
||||
usermain = testcfg['main'] = config.IdleUserConfParser('') # filename
|
||||
userhigh = testcfg['highlight'] = config.IdleUserConfParser('')
|
||||
userkeys = testcfg['keys'] = config.IdleUserConfParser('')
|
||||
|
||||
def setUpModule():
|
||||
idleConf.userCfg = testcfg
|
||||
|
||||
def tearDownModule():
|
||||
idleConf.userCfg = testcfg
|
||||
|
||||
|
||||
class CurrentColorKeysTest(unittest.TestCase):
|
||||
"""Test correct scenarios for colorkeys and wrap functions.
|
||||
|
||||
The 5 correct patterns are possible results of config dialog.
|
||||
"""
|
||||
colorkeys = idleConf.current_colors_and_keys
|
||||
|
||||
def test_old_default(self):
|
||||
# name2 must be blank
|
||||
usermain.read_string('''
|
||||
[Theme]
|
||||
default= 1
|
||||
''')
|
||||
self.assertEqual(self.colorkeys('Theme'), 'IDLE Classic')
|
||||
usermain['Theme']['name'] = 'IDLE New'
|
||||
self.assertEqual(self.colorkeys('Theme'), 'IDLE New')
|
||||
usermain['Theme']['name'] = 'non-default' # error
|
||||
self.assertEqual(self.colorkeys('Theme'), 'IDLE Classic')
|
||||
usermain.remove_section('Theme')
|
||||
|
||||
def test_new_default(self):
|
||||
# name2 overrides name
|
||||
usermain.read_string('''
|
||||
[Theme]
|
||||
default= 1
|
||||
name= IDLE New
|
||||
name2= IDLE Dark
|
||||
''')
|
||||
self.assertEqual(self.colorkeys('Theme'), 'IDLE Dark')
|
||||
usermain['Theme']['name2'] = 'non-default' # error
|
||||
self.assertEqual(self.colorkeys('Theme'), 'IDLE Classic')
|
||||
usermain.remove_section('Theme')
|
||||
|
||||
def test_user_override(self):
|
||||
# name2 does not matter
|
||||
usermain.read_string('''
|
||||
[Theme]
|
||||
default= 0
|
||||
name= Custom Dark
|
||||
''') # error until set userhigh
|
||||
self.assertEqual(self.colorkeys('Theme'), 'IDLE Classic')
|
||||
userhigh.read_string('[Custom Dark]\na=b')
|
||||
self.assertEqual(self.colorkeys('Theme'), 'Custom Dark')
|
||||
usermain['Theme']['name2'] = 'IDLE Dark'
|
||||
self.assertEqual(self.colorkeys('Theme'), 'Custom Dark')
|
||||
usermain.remove_section('Theme')
|
||||
userhigh.remove_section('Custom Dark')
|
||||
|
||||
|
||||
class WarningTest(unittest.TestCase):
|
||||
|
||||
def test_warn(self):
|
||||
Equal = self.assertEqual
|
||||
config._warned = set()
|
||||
with captured_stderr() as stderr:
|
||||
config._warn('warning', 'key')
|
||||
Equal(config._warned, {('warning','key')})
|
||||
Equal(stderr.getvalue(), 'warning'+'\n')
|
||||
with captured_stderr() as stderr:
|
||||
config._warn('warning', 'key')
|
||||
Equal(stderr.getvalue(), '')
|
||||
with captured_stderr() as stderr:
|
||||
config._warn('warn2', 'yek')
|
||||
Equal(config._warned, {('warning','key'), ('warn2','yek')})
|
||||
Equal(stderr.getvalue(), 'warn2'+'\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(verbosity=2)
|
Loading…
Reference in New Issue