Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions Doc/library/idle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,23 @@ If there are arguments:
* Otherwise, arguments are files opened for editing and
``sys.argv`` reflects the arguments passed to IDLE itself.


Optional Startup Code Execution
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In addition to the ``-``, ``-s``, ``-c``, and ``-r`` command line options for
executing Python code upon startup, code can be entered using the IDLE
Configuration Dialog under the ``Startup`` tab. The code entered here will
be executed if the appropriate check box is selected for running on
startup and if command line options ``-``, ``-c``, and ``-r`` were not used.
Those options take precedence and preclude the configuration code from running.
However, the configuration-level code will be executed before the ``-s``
option file is run.

Note that the configuration code isn't checked for errors. If it can't be
executed, then the shell may show errors upon starting.


Startup failure
^^^^^^^^^^^^^^^

Expand Down
7 changes: 6 additions & 1 deletion Lib/idlelib/config-main.def
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,14 @@ font-size= 10
font-bold= 0
encoding= none
line-numbers-default= 0
editor-template-code=

[PyShell]
[ShellWindow]
line-numbers-default= 0
auto-squeeze-min-lines= 50
startup-code-on= False
restart-code-on= False
shell-startup-code=

[Indent]
use-spaces= 1
Expand Down
172 changes: 172 additions & 0 deletions Lib/idlelib/configdialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,13 @@ def create_widgets(self):
self.fontpage = FontPage(note, self.highpage)
self.keyspage = KeysPage(note)
self.genpage = GenPage(note)
self.startpage = StartPage(note)
self.extpage = self.create_page_extensions()
note.add(self.fontpage, text='Fonts/Tabs')
note.add(self.highpage, text='Highlights')
note.add(self.keyspage, text=' Keys ')
note.add(self.genpage, text=' General ')
note.add(self.startpage, text=' Startup ')
note.add(self.extpage, text='Extensions')
note.enable_traversal()
note.pack(side=TOP, expand=TRUE, fill=BOTH)
Expand Down Expand Up @@ -2196,6 +2198,176 @@ def update_help_changes(self):
';'.join(self.user_helplist[num-1][:2]))


class StartPage(Frame):

def __init__(self, master):
super().__init__(master)
self.create_page_startup()
self.load_startup_cfg()

def create_page_startup(self):
"""Return frame of widgets for Startup tab.

Enable users to provisionally change startup options. Function
load_startup_cfg intializes tk variables using idleConf.
Radiobuttons startup_shell_on and startup_editor_on
set var startup_edit. Entry boxes win_width_int and win_height_int
set var win_width and win_height. Setting var_name invokes the
default callback that adds option to changes.

Widgets for StartupPage(Frame): (*) widgets bound to self
frame_window: LabelFrame
frame_run: Frame
startup_title: Label
(*)startup_editor_on: Radiobutton - startup_edit
(*)startup_shell_on: Radiobutton - startup_edit
frame_win_size: Frame
win_size_title: Label
win_width_title: Label
(*)win_width_int: Entry - win_width
win_height_title: Label
(*)win_height_int: Entry - win_height
frame_code: Frame
frame_code_shell: Frame
(*)shell_startup_toggle: Checkbutton - startup_code_on
(*)shell_restart_toggle: Checkbutton - restart_code_on
(*)shell_startup_text: Text
frame_code_editor: Frame
(*)editor_template_text: Text
"""
# Integer values need StringVar because int('') raises.
self.startup_edit = tracers.add(
IntVar(self), ('main', 'General', 'editor-on-startup'))
self.win_width = tracers.add(
StringVar(self), ('main', 'EditorWindow', 'width'))
self.win_height = tracers.add(
StringVar(self), ('main', 'EditorWindow', 'height'))
self.startup_code_on = tracers.add(
BooleanVar(self), ('main', 'ShellWindow', 'startup-code-on'))
self.restart_code_on = tracers.add(
BooleanVar(self), ('main', 'ShellWindow', 'restart-code-on'))

# Create widgets:
# Section frames.
frame_window = LabelFrame(self, borderwidth=2, relief=GROOVE,
text=' Window Preferences')
frame_shell = LabelFrame(self, borderwidth=2, relief=GROOVE,
text=' Shell Startup Code ')
frame_editor = LabelFrame(self, borderwidth=2, relief=GROOVE,
text=' Editor Template Code ')

# Frame_window.
frame_run = Frame(frame_window, borderwidth=0)
startup_title = Label(frame_run, text='At Startup')
self.startup_editor_on = Radiobutton(
frame_run, variable=self.startup_edit, value=1,
text="Open Edit Window")
self.startup_shell_on = Radiobutton(
frame_run, variable=self.startup_edit, value=0,
text='Open Shell Window')

frame_win_size = Frame(frame_window, borderwidth=0)
win_size_title = Label(
frame_win_size, text='Initial Window Size (in characters)')
win_width_title = Label(frame_win_size, text='Width')
self.win_width_int = Entry(
frame_win_size, textvariable=self.win_width, width=3)
win_height_title = Label(frame_win_size, text='Height')
self.win_height_int = Entry(
frame_win_size, textvariable=self.win_height, width=3)

# Frame_shell.
frame_shell_toggle = Frame(frame_shell)
self.shell_startup_toggle = Checkbutton(frame_shell_toggle,
variable=self.startup_code_on,
onvalue=True, offvalue=False,
text='Run code on startup')
self.shell_restart_toggle = Checkbutton(frame_shell_toggle,
variable=self.restart_code_on,
onvalue=True, offvalue=False,
text='Run code on restart')
self.shell_startup_text = Text(frame_shell, width=20, height=10)
scroll_shell = Scrollbar(frame_shell)
scroll_shell['command'] = self.shell_startup_text.yview
self.shell_startup_text['yscrollcommand'] = scroll_shell.set

# Frame_editor.
self.editor_template_text = Text(frame_editor, width=20, height=10)
scroll_editor = Scrollbar(frame_editor)
scroll_editor['command'] = self.editor_template_text.yview
self.editor_template_text['yscrollcommand'] = scroll_editor.set

# Pack widgets:
# Body.
frame_window.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
# frame_run.
frame_run.pack(side=TOP, padx=5, pady=0, fill=X)
startup_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
self.startup_shell_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
self.startup_editor_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
# frame_win_size.
frame_win_size.pack(side=TOP, padx=5, pady=0, fill=X)
win_size_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
self.win_height_int.pack(side=RIGHT, anchor=E, padx=10, pady=5)
win_height_title.pack(side=RIGHT, anchor=E, pady=5)
self.win_width_int.pack(side=RIGHT, anchor=E, padx=10, pady=5)
win_width_title.pack(side=RIGHT, anchor=E, pady=5)
# Frame_shell.
frame_shell.pack(side='top', padx=5, pady=5, expand=True, fill='both')
frame_shell_toggle.pack(side='top')
self.shell_startup_toggle.pack(side='left', padx=2, pady=2)
self.shell_restart_toggle.pack(side='right', padx=2, pady=2)
scroll_shell.pack(side='right', anchor='w', fill='y')
self.shell_startup_text.pack(fill='x')
# Frame_editor.
frame_editor.pack(side='top', padx=5, pady=0, fill='x')
scroll_editor.pack(side='right', anchor='w', fill='y')
self.editor_template_text.pack(fill='x')

def load_startup_cfg(self):
"Load current configuration settings for the startup options."
# Set variables for all windows.
self.startup_edit.set(idleConf.GetOption(
'main', 'General', 'editor-on-startup', type='bool'))
self.win_width.set(idleConf.GetOption(
'main', 'EditorWindow', 'width', type='int'))
self.win_height.set(idleConf.GetOption(
'main', 'EditorWindow', 'height', type='int'))

self.startup_code_on.set(idleConf.GetOption(
'main', 'ShellWindow', 'startup-code-on', type='bool'))
self.restart_code_on.set(idleConf.GetOption(
'main', 'ShellWindow', 'restart-code-on', type='bool'))
shell_code = idleConf.GetOption(
'main', 'ShellWindow', 'shell-startup-code')
self.shell_startup_text.insert('end', shell_code or '')
self.shell_startup_text.edit_modified(False)
# Text widgets don't have trace methods, but instead set a
# modified flag on inserts or deletes.
self.shell_startup_text.bind('<<Modified>>',
self.var_changed_shell_text)

editor_template = idleConf.GetOption(
'main', 'EditorWindow', 'editor-template-code')
self.editor_template_text.insert('end', editor_template or '')
self.editor_template_text.edit_modified(False)
self.editor_template_text.bind('<<Modified>>',
self.var_changed_editor_template)

def var_changed_shell_text(self, *params):
"Store changes to shell startup text."
value = self.shell_startup_text.get('1.0', 'end-1c')
changes.add_option('main', 'ShellWindow', 'shell-startup-code', value)
self.shell_startup_text.edit_modified(False)

def var_changed_editor_template(self, *params):
"Store changes to editor template text."
value = self.editor_template_text.get('1.0', 'end-1c')
changes.add_option('main', 'EditorWindow',
'editor-template-code', value)
self.editor_template_text.edit_modified(False)


class VarTrace:
"""Maintain Tk variables trace state."""

Expand Down
9 changes: 8 additions & 1 deletion Lib/idlelib/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,15 @@ def set_width(self):
self.width = pixel_width // zero_char_width

def new_callback(self, event):
"""Create a new editor window.

A new editor is created with default template text.
"""
dirname, basename = self.io.defaultfilename()
self.flist.new(dirname)
editor = self.flist.new(dirname)
template = idleConf.GetOption('main', 'EditorWindow',
'editor-template-code')
editor.text.insert('end', template or '')
return "break"

def home_callback(self, event):
Expand Down
4 changes: 2 additions & 2 deletions Lib/idlelib/idle_test/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,11 +342,11 @@ def test_get_section_list(self):

self.assertCountEqual(
conf.GetSectionList('default', 'main'),
['General', 'EditorWindow', 'PyShell', 'Indent', 'Theme',
['General', 'EditorWindow', 'ShellWindow', 'Indent', 'Theme',
'Keys', 'History', 'HelpFiles'])
self.assertCountEqual(
conf.GetSectionList('user', 'main'),
['General', 'EditorWindow', 'PyShell', 'Indent', 'Theme',
['General', 'EditorWindow', 'ShellWindow', 'Indent', 'Theme',
'Keys', 'History', 'HelpFiles'])

with self.assertRaises(config.InvalidConfigSet):
Expand Down
111 changes: 105 additions & 6 deletions Lib/idlelib/idle_test/test_configdialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

Half the class creates dialog, half works with user customizations.
"""
import os
from idlelib import configdialog
from test.support import requires
requires('gui')
Expand Down Expand Up @@ -1232,18 +1233,12 @@ def test_load_general_cfg(self):
# Set to wrong values, load, check right values.
eq = self.assertEqual
d = self.page
d.startup_edit.set(1)
d.autosave.set(1)
d.win_width.set(1)
d.win_height.set(1)
d.helplist.insert('end', 'bad')
d.user_helplist = ['bad', 'worse']
idleConf.SetOption('main', 'HelpFiles', '1', 'name;file')
d.load_general_cfg()
eq(d.startup_edit.get(), 0)
eq(d.autosave.get(), 0)
eq(d.win_width.get(), '80')
eq(d.win_height.get(), '40')
eq(d.helplist.get(0, 'end'), ('name',))
eq(d.user_helplist, [('name', 'file', '1')])

Expand Down Expand Up @@ -1441,6 +1436,110 @@ def test_update_help_changes(self):
d.update_help_changes = Func()


class StartPageTest(unittest.TestCase):
"""Test that startup tab widgets enable users to make changes.

Test that widget actions set vars and that var changes add
options.
"""
@classmethod
def setUpClass(cls):
page = cls.page = dialog.startpage
dialog.note.select(page)

@classmethod
def tearDownClass(cls):
page = cls.page

def setUp(self):
changes.clear()

def test_load_startup_cfg(self):
# Set to wrong values, load, check right values.
eq = self.assertEqual
d = self.page
d.startup_edit.set(1)
d.win_width.set(1)
d.win_height.set(1)
d.startup_code_on.set(1)
d.restart_code_on.set(1)
d.shell_startup_text.insert('end', 'shell spam')
d.editor_template_text.insert('end', 'editor spam')
d.load_startup_cfg()
eq(d.startup_edit.get(), 0)
eq(d.win_width.get(), '80')
eq(d.win_height.get(), '40')
eq(d.startup_code_on.get(), False)
eq(d.restart_code_on.get(), False)
self.assertNotIn('spam', d.shell_startup_text.get('1.0'))
self.assertNotIn('spam', d.editor_template_text.get('1.0'))

def test_startup(self):
d = self.page
d.startup_editor_on.invoke()
self.assertEqual(mainpage,
{'General': {'editor-on-startup': '1'}})
changes.clear()
d.startup_shell_on.invoke()
self.assertEqual(mainpage,
{'General': {'editor-on-startup': '0'}})

def test_editor_size(self):
d = self.page
d.win_height_int.delete(0, 'end')
d.win_height_int.insert(0, '11')
self.assertEqual(mainpage, {'EditorWindow': {'height': '11'}})
changes.clear()
d.win_width_int.delete(0, 'end')
d.win_width_int.insert(0, '11')
self.assertEqual(mainpage, {'EditorWindow': {'width': '11'}})

def test_startup_code_on(self):
d = self.page
d.shell_startup_toggle.invoke()
self.assertEqual(mainpage,
{'ShellWindow': {'startup-code-on': 'True'}})
changes.clear()
d.shell_startup_toggle.invoke()
self.assertEqual(mainpage,
{'ShellWindow': {'startup-code-on': 'False'}})

def test_restart_code_on(self):
d = self.page
d.shell_restart_toggle.invoke()
self.assertEqual(mainpage,
{'ShellWindow': {'restart-code-on': 'True'}})
changes.clear()
d.shell_restart_toggle.invoke()
self.assertEqual(mainpage,
{'ShellWindow': {'restart-code-on': 'False'}})

def test_shell_startup_text(self):
d = self.page
d.shell_startup_text.delete('1.0', 'end')
text = f'import os{os.linesep}import re'
d.shell_startup_text.insert('end', text)
self.assertEqual(mainpage,
{'ShellWindow': {'shell-startup-code': text}})
changes.clear()
d.shell_startup_text.delete('1.0', 'end')
self.assertEqual(mainpage,
{'ShellWindow': {'shell-startup-code': ''}})

def test_editor_template_text(self):
d = self.page
d.editor_template_text.delete('1.0', 'end')
text = f'# This is a comment.{os.linesep}# Second line'
d.editor_template_text.insert('end', text)
self.assertEqual(
mainpage,
{'EditorWindow': {'editor-template-code': text}})
changes.clear()
d.editor_template_text.delete('1.0', 'end')
self.assertEqual(mainpage,
{'EditorWindow': {'editor-template-code': ''}})


class VarTraceTest(unittest.TestCase):

@classmethod
Expand Down
Loading