Merge heads

This commit is contained in:
Serhiy Storchaka 2016-07-10 21:34:25 +03:00
commit 763e04b442
7 changed files with 274 additions and 61 deletions

View File

@ -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!

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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__':

View File

@ -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.
''',
}

View File

@ -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)