This commit is contained in:
ton
2023-10-05 02:17:01 +07:00
parent 6b7a8a3482
commit fef77e218f
5452 changed files with 919218 additions and 7 deletions

47
.CondaPkg/env/Lib/idlelib/CREDITS.txt vendored Normal file
View File

@@ -0,0 +1,47 @@
Guido van Rossum, as well as being the creator of the Python language, is the
original creator of IDLE. Other contributors prior to Version 0.8 include
Mark Hammond, Jeremy Hylton, Tim Peters, and Moshe Zadka.
Until Python 2.3, IDLE's development was carried out in the SF IDLEfork project. The
objective was to develop a version of IDLE which had an execution environment
which could be initialized prior to each run of user code.
IDLefork was merged into the Python code base in 2003.
The IDLEfork project was initiated by David Scherer, with some help from Peter
Schneider-Kamp and Nicholas Riley. David wrote the first version of the RPC
code and designed a fast turn-around environment for VPython. Guido developed
the RPC code and Remote Debugger currently integrated in IDLE. Bruce Sherwood
contributed considerable time testing and suggesting improvements.
Besides David and Guido, the main developers who were active on IDLEfork
are Stephen M. Gava, who implemented the configuration GUI, the new
configuration system, and the About dialog, and Kurt B. Kaiser, who completed
the integration of the RPC and remote debugger, implemented the threaded
subprocess, and made a number of usability enhancements.
Other contributors include Raymond Hettinger, Tony Lownds (Mac integration),
Neal Norwitz (code check and clean-up), Ronald Oussoren (Mac integration),
Noam Raphael (Code Context, Call Tips, many other patches), and Chui Tey (RPC
integration, debugger integration and persistent breakpoints).
Scott David Daniels, Tal Einat, Hernan Foffani, Christos Georgiou,
Jim Jewett, Martin v. Löwis, Jason Orendorff, Guilherme Polo, Josh Robb,
Nigel Rowe, Bruce Sherwood, Jeff Shute, and Weeble have submitted useful
patches. Thanks, guys!
Major contributors since 2005:
- 2005: Tal Einat
- 2010: Terry Jan Reedy (current maintainer)
- 2013: Roger Serwys
- 2014: Saimadhav Heblikar
- 2015: Mark Roseman
- 2017: Louie Lu, Cheryl Sabella, and Serhiy Storchaka
For additional details refer to NEWS.txt and Changelog.
Please contact the IDLE maintainer (kbk@shore.net) to have yourself included
here if you are one of those we missed!

1591
.CondaPkg/env/Lib/idlelib/ChangeLog vendored Normal file

File diff suppressed because it is too large Load Diff

296
.CondaPkg/env/Lib/idlelib/HISTORY.txt vendored Normal file
View File

@@ -0,0 +1,296 @@
IDLE History
============
This file contains the release messages for previous IDLE releases.
As you read on you go back to the dark ages of IDLE's history.
What's New in IDLEfork 0.8.1?
=============================
*Release date: 22-Jul-2001*
- New tarball released as a result of the 'revitalisation' of the IDLEfork
project.
- This release requires python 2.1 or better. Compatibility with earlier
versions of python (especially ancient ones like 1.5x) is no longer a
priority in IDLEfork development.
- This release is based on a merging of the earlier IDLE fork work with current
cvs IDLE (post IDLE version 0.8), with some minor additional coding by Kurt
B. Kaiser and Stephen M. Gava.
- This release is basically functional but also contains some known breakages,
particularly with running things from the shell window. Also the debugger is
not working, but I believe this was the case with the previous IDLE fork
release (0.7.1) as well.
- This release is being made now to mark the point at which IDLEfork is
launching into a new stage of development.
- IDLEfork CVS will now be branched to enable further development and
exploration of the two "execution in a remote process" patches submitted by
David Scherer (David's is currently in IDLEfork) and GvR, while stabilisation
and development of less heavyweight improvements (like user customisation)
can continue on the trunk.
What's New in IDLEfork 0.7.1?
==============================
*Release date: 15-Aug-2000*
- First project tarball released.
- This was the first release of IDLE fork, which at this stage was a
combination of IDLE 0.5 and the VPython idle fork, with additional changes
coded by David Scherer, Peter Schneider-Kamp and Nicholas Riley.
IDLEfork 0.7.1 - 29 May 2000
-----------------------------
David Scherer <dscherer@cmu.edu>
- This is a modification of the CVS version of IDLE 0.5, updated as of
2000-03-09. It is alpha software and might be unstable. If it breaks, you
get to keep both pieces.
- If you have problems or suggestions, you should either contact me or post to
the list at http://www.python.org/mailman/listinfo/idle-dev (making it clear
that you are using this modified version of IDLE).
- Changes:
- The ExecBinding module, a replacement for ScriptBinding, executes programs
in a separate process, piping standard I/O through an RPC mechanism to an
OnDemandOutputWindow in IDLE. It supports executing unnamed programs
(through a temporary file). It does not yet support debugging.
- When running programs with ExecBinding, tracebacks will be clipped to
exclude system modules. If, however, a system module calls back into the
user program, that part of the traceback will be shown.
- The OnDemandOutputWindow class has been improved. In particular, it now
supports a readline() function used to implement user input, and a
scroll_clear() operation which is used to hide the output of a previous run
by scrolling it out of the window.
- Startup behavior has been changed. By default IDLE starts up with just a
blank editor window, rather than an interactive window. Opening a file in
such a blank window replaces the (nonexistent) contents of that window
instead of creating another window. Because of the need to have a
well-known port for the ExecBinding protocol, only one copy of IDLE can be
running. Additional invocations use the RPC mechanism to report their
command line arguments to the copy already running.
- The menus have been reorganized. In particular, the excessively large
'edit' menu has been split up into 'edit', 'format', and 'run'.
- 'Python Documentation' now works on Windows, if the win32api module is
present.
- A few key bindings have been changed: F1 now loads Python Documentation
instead of the IDLE help; shift-TAB is now a synonym for unindent.
- New modules:
ExecBinding.py Executes program through loader
loader.py Bootstraps user program
protocol.py RPC protocol
Remote.py User-process interpreter
spawn.py OS-specific code to start programs
- Files modified:
autoindent.py ( bindings tweaked )
bindings.py ( menus reorganized )
config.txt ( execbinding enabled )
editorwindow.py ( new menus, fixed 'Python Documentation' )
filelist.py ( hook for "open in same window" )
formatparagraph.py ( bindings tweaked )
idle.bat ( removed absolute pathname )
idle.pyw ( weird bug due to import with same name? )
iobinding.py ( open in same window, EOL convention )
keydefs.py ( bindings tweaked )
outputwindow.py ( readline, scroll_clear, etc )
pyshell.py ( changed startup behavior )
readme.txt ( <Recursion on file with id=1234567> )
IDLE 0.5 - February 2000 - Release Notes
----------------------------------------
This is an early release of IDLE, my own attempt at a Tkinter-based
IDE for Python.
(For a more detailed change log, see the file ChangeLog.)
FEATURES
IDLE has the following features:
- coded in 100% pure Python, using the Tkinter GUI toolkit (i.e. Tcl/Tk)
- cross-platform: works on Windows and Unix (on the Mac, there are
currently problems with Tcl/Tk)
- multi-window text editor with multiple undo, Python colorizing
and many other features, e.g. smart indent and call tips
- Python shell window (a.k.a. interactive interpreter)
- debugger (not complete, but you can set breakpoints, view and step)
USAGE
The main program is in the file "idle.py"; on Unix, you should be able
to run it by typing "./idle.py" to your shell. On Windows, you can
run it by double-clicking it; you can use idle.pyw to avoid popping up
a DOS console. If you want to pass command line arguments on Windows,
use the batch file idle.bat.
Command line arguments: files passed on the command line are executed,
not opened for editing, unless you give the -e command line option.
Try "./idle.py -h" to see other command line options.
IDLE requires Python 1.5.2, so it is currently only usable with a
Python 1.5.2 distribution. (An older version of IDLE is distributed
with Python 1.5.2; you can drop this version on top of it.)
COPYRIGHT
IDLE is covered by the standard Python copyright notice
(http://www.python.org/doc/Copyright.html).
New in IDLE 0.5 (2/15/2000)
---------------------------
Tons of stuff, much of it contributed by Tim Peters and Mark Hammond:
- Status bar, displaying current line/column (Moshe Zadka).
- Better stack viewer, using tree widget. (XXX Only used by Stack
Viewer menu, not by the debugger.)
- Format paragraph now recognizes Python block comments and reformats
them correctly (MH)
- New version of pyclbr.py parses top-level functions and understands
much more of Python's syntax; this is reflected in the class and path
browsers (TP)
- Much better auto-indent; knows how to indent the insides of
multi-line statements (TP)
- Call tip window pops up when you type the name of a known function
followed by an open parenthesis. Hit ESC or click elsewhere in the
window to close the tip window (MH)
- Comment out region now inserts ## to make it stand out more (TP)
- New path and class browsers based on a tree widget that looks
familiar to Windows users
- Reworked script running commands to be more intuitive: I/O now
always goes to the *Python Shell* window, and raw_input() works
correctly. You use F5 to import/reload a module: this adds the module
name to the __main__ namespace. You use Control-F5 to run a script:
this runs the script *in* the __main__ namespace. The latter also
sets sys.argv[] to the script name
New in IDLE 0.4 (4/7/99)
------------------------
Most important change: a new menu entry "File -> Path browser", shows
a 4-column hierarchical browser which lets you browse sys.path,
directories, modules, and classes. Yes, it's a superset of the Class
browser menu entry. There's also a new internal module,
MultiScrolledLists.py, which provides the framework for this dialog.
New in IDLE 0.3 (2/17/99)
-------------------------
Most important changes:
- Enabled support for running a module, with or without the debugger.
Output goes to a new window. Pressing F5 in a module is effectively a
reload of that module; Control-F5 loads it under the debugger.
- Re-enable tearing off the Windows menu, and make a torn-off Windows
menu update itself whenever a window is opened or closed.
- Menu items can now be have a checkbox (when the menu label starts
with "!"); use this for the Debugger and "Auto-open stack viewer"
(was: JIT stack viewer) menu items.
- Added a Quit button to the Debugger API.
- The current directory is explicitly inserted into sys.path.
- Fix the debugger (when using Python 1.5.2b2) to use canonical
filenames for breakpoints, so these actually work. (There's still a
lot of work to be done to the management of breakpoints in the
debugger though.)
- Closing a window that is still colorizing now actually works.
- Allow dragging of the separator between the two list boxes in the
class browser.
- Bind ESC to "close window" of the debugger, stack viewer and class
browser. It removes the selection highlighting in regular text
windows. (These are standard Windows conventions.)
New in IDLE 0.2 (1/8/99)
------------------------
Lots of changes; here are the highlights:
General:
- You can now write and configure your own IDLE extension modules; see
extend.txt.
File menu:
The command to open the Python shell window is now in the File menu.
Edit menu:
New Find dialog with more options; replace dialog; find in files dialog.
Commands to tabify or untabify a region.
Command to format a paragraph.
Debug menu:
JIT (Just-In-Time) stack viewer toggle -- if set, the stack viewer
automaticall pops up when you get a traceback.
Windows menu:
Zoom height -- make the window full height.
Help menu:
The help text now show up in a regular window so you can search and
even edit it if you like.
IDLE 0.1 was distributed with the Python 1.5.2b1 release on 12/22/98.
======================================================================

View File

@@ -0,0 +1,13 @@
The IDLE icons are from https://bugs.python.org/issue1490384
Created by Andrew Clover.
The original sources are available from Andrew's website:
https://www.doxdesk.com/software/py/pyicons.html
Various different formats and sizes are available at this GitHub Pull Request:
https://github.com/python/cpython/pull/17473
The idle.ico file was created with ImageMagick:
$ convert idle_16.png idle_32.png idle_48.png idle_256.png idle.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

BIN
.CondaPkg/env/Lib/idlelib/Icons/idle.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1019 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

BIN
.CondaPkg/env/Lib/idlelib/Icons/tk.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 B

1340
.CondaPkg/env/Lib/idlelib/NEWS.txt vendored Normal file

File diff suppressed because it is too large Load Diff

660
.CondaPkg/env/Lib/idlelib/NEWS2x.txt vendored Normal file
View File

@@ -0,0 +1,660 @@
What's New in IDLE 2.7? (Merged into 3.1 before 2.7 release.)
=======================
*Release date: XX-XXX-2010*
- idle.py modified and simplified to better support developing experimental
versions of IDLE which are not installed in the standard location.
- OutputWindow/PyShell right click menu "Go to file/line" wasn't working with
file paths containing spaces. Bug 5559.
- Windows: Version string for the .chm help file changed, file not being
accessed Patch 5783 Guilherme Polo
- Allow multiple IDLE GUI/subprocess pairs to exist simultaneously. Thanks to
David Scherer for suggesting the use of an ephemeral port for the GUI.
Patch 1529142 Weeble.
- Remove port spec from run.py and fix bug where subprocess fails to
extract port from command line when warnings are present.
- Tk 8.5 Text widget requires 'wordprocessor' tabstyle attr to handle
mixed space/tab properly. Issue 5129, patch by Guilherme Polo.
- Issue #3549: On MacOS the preferences menu was not present
- IDLE would print a "Unhandled server exception!" message when internal
debugging is enabled.
- Issue #4455: IDLE failed to display the windows list when two windows have
the same title.
- Issue #4383: When IDLE cannot make the connection to its subprocess, it would
fail to properly display the error message.
- help() was not paging to the shell. Issue1650.
- CodeContext was not importing.
- Corrected two 3.0 compatibility errors reported by Mark Summerfield:
http://mail.python.org/pipermail/python-3000/2007-December/011491.html
- Shell was not colorizing due to bug introduced at r57998, Bug 1586.
- Issue #1585: IDLE uses non-existent xrange() function.
- Windows EOL sequence not converted correctly, encoding error.
Caused file save to fail. Bug 1130.
- IDLE converted to Python 3000 syntax.
- Strings became Unicode.
- CallTips module now uses the inspect module to produce the argspec.
- IDLE modules now use absolute import instead of implied relative import.
- atexit call replaces sys.exitfunc. The functionality of delete-exitfunc flag
in config-main.cfg remains unchanged: if set, registered exit functions will
be cleared before IDLE exits.
What's New in IDLE 2.6
======================
*Release date: 01-Oct-2008*, merged into 3.0 releases detailed above (3.0rc2)
- Issue #2665: On Windows, an IDLE installation upgraded from an old version
would not start if a custom theme was defined.
- Home / Control-A toggles between left margin and end of leading white
space. issue1196903, patch by Jeff Shute.
- Improved AutoCompleteWindow logic. issue2062, patch by Tal Einat.
- Autocompletion of filenames now support alternate separators, e.g. the
'/' char on Windows. issue2061 Patch by Tal Einat.
- Configured selection highlighting colors were ignored; updating highlighting
in the config dialog would cause non-Python files to be colored as if they
were Python source; improve use of ColorDelagator. Patch 1334. Tal Einat.
- ScriptBinding event handlers weren't returning 'break'. Patch 2050, Tal Einat
- There was an error on exit if no sys.exitfunc was defined. Issue 1647.
- Could not open files in .idlerc directory if latter was hidden on Windows.
Issue 1743, Issue 1862.
- Configure Dialog: improved layout for keybinding. Patch 1457 Tal Einat.
- tabpage.py updated: tabbedPages.py now supports multiple dynamic rows
of tabs. Patch 1612746 Tal Einat.
- Add confirmation dialog before printing. Patch 1717170 Tal Einat.
- Show paste position if > 80 col. Patch 1659326 Tal Einat.
- Update cursor color without restarting. Patch 1725576 Tal Einat.
- Allow keyboard interrupt only when user code is executing in subprocess.
Patch 1225 Tal Einat (reworked from IDLE-Spoon).
- configDialog cleanup. Patch 1730217 Tal Einat.
- textView cleanup. Patch 1718043 Tal Einat.
- Clean up EditorWindow close.
- Patch 1693258: Fix for duplicate "preferences" menu-OS X. Backport of r56204.
- OSX: Avoid crash for those versions of Tcl/Tk which don't have a console
- Bug in idlelib.MultiCall: Options dialog was crashing IDLE if there was an
option in config-extensions w/o a value. Patch #1672481, Tal Einat
- Corrected some bugs in AutoComplete. Also, Page Up/Down in ACW implemented;
mouse and cursor selection in ACWindow implemented; double Tab inserts
current selection and closes ACW (similar to double-click and Return); scroll
wheel now works in ACW. Added AutoComplete instructions to IDLE Help.
- AutoCompleteWindow moved below input line, will move above if there
isn't enough space. Patch 1621265 Tal Einat
- Calltips now 'handle' tuples in the argument list (display '<tuple>' :)
Suggested solution by Christos Georgiou, Bug 791968.
- Add 'raw' support to configHandler. Patch 1650174 Tal Einat.
- Avoid hang when encountering a duplicate in a completion list. Bug 1571112.
- Patch #1362975: Rework CodeContext indentation algorithm to
avoid hard-coding pixel widths.
- Bug #813342: Start the IDLE subprocess with -Qnew if the parent
is started with that option.
- Honor the "Cancel" action in the save dialog (Debian bug #299092)
- Some syntax errors were being caught by tokenize during the tabnanny
check, resulting in obscure error messages. Do the syntax check
first. Bug 1562716, 1562719
- IDLE's version number takes a big jump to match the version number of
the Python release of which it's a part.
What's New in IDLE 1.2?
=======================
*Release date: 19-SEP-2006*
- File menu hotkeys: there were three 'p' assignments. Reassign the
'Save Copy As' and 'Print' hotkeys to 'y' and 't'. Change the
Shell hotkey from 's' to 'l'.
- IDLE honors new quit() and exit() commands from site.py Quitter() object.
Patch 1540892, Jim Jewett
- The 'with' statement is now a Code Context block opener.
Patch 1540851, Jim Jewett
- Retrieval of previous shell command was not always preserving indentation
(since 1.2a1) Patch 1528468 Tal Einat.
- Changing tokenize (39046) to detect dedent broke tabnanny check (since 1.2a1)
- ToggleTab dialog was setting indent to 8 even if cancelled (since 1.2a1).
- When used w/o subprocess, all exceptions were preceded by an error
message claiming they were IDLE internal errors (since 1.2a1).
- Bug #1525817: Don't truncate short lines in IDLE's tool tips.
- Bug #1517990: IDLE keybindings on MacOS X now work correctly
- Bug #1517996: IDLE now longer shows the default Tk menu when a
path browser, class browser or debugger is the frontmost window on MacOS X
- EditorWindow.test() was failing. Bug 1417598
- EditorWindow failed when used stand-alone if sys.ps1 not set.
Bug 1010370 Dave Florek
- Tooltips failed on new-syle class __init__ args. Bug 1027566 Loren Guthrie
- Avoid occasional failure to detect closing paren properly.
Patch 1407280 Tal Einat
- Rebinding Tab key was inserting 'tab' instead of 'Tab'. Bug 1179168.
- Colorizer now handles #<builtin> correctly, also unicode strings and
'as' keyword in comment directly following import command. Closes 1325071.
Patch 1479219 Tal Einat
- Patch #1162825: Support non-ASCII characters in IDLE window titles.
- Source file f.flush() after writing; trying to avoid lossage if user
kills GUI.
- Options / Keys / Advanced dialog made functional. Also, allow binding
of 'movement' keys.
- 'syntax' patch adds improved calltips and a new class attribute listbox.
MultiCall module allows binding multiple actions to an event.
Patch 906702 Noam Raphael
- Better indentation after first line of string continuation.
IDLEfork Patch 681992, Noam Raphael
- Fixed CodeContext alignment problem, following suggestion from Tal Einat.
- Increased performance in CodeContext extension Patch 936169 Noam Raphael
- Mac line endings were incorrect when pasting code from some browsers
when using X11 and the Fink distribution. Python Bug 1263656.
- <Enter> when cursor is on a previous command retrieves that command. Instead
of replacing the input line, the previous command is now appended to the
input line. Indentation is preserved, and undo is enabled.
Patch 1196917 Jeff Shute
- Clarify "tab/space" Error Dialog and "Tab Width" Dialog associated with
the Untabify command.
- Corrected "tab/space" Error Dialog to show correct menu for Untabify.
Patch 1196980 Jeff Shute
- New files are colorized by default, and colorizing is removed when
saving as non-Python files. Patch 1196895 Jeff Shute
Closes Python Bugs 775012 and 800432, partial fix IDLEfork 763524
- Improve subprocess link error notification.
- run.py: use Queue's blocking feature instead of sleeping in the main
loop. Patch # 1190163 Michiel de Hoon
- Add config-main option to make the 'history' feature non-cyclic.
Default remains cyclic. Python Patch 914546 Noam Raphael.
- Removed ability to configure tabs indent from Options dialog. This 'feature'
has never worked and no one has complained. It is still possible to set a
default tabs (v. spaces) indent 'manually' via config-main.def (or to turn on
tabs for the current EditorWindow via the Format menu) but IDLE will
encourage indentation via spaces.
- Enable setting the indentation width using the Options dialog.
Bug # 783877
- Add keybindings for del-word-left and del-word-right.
- Discourage using an indent width other than 8 when using tabs to indent
Python code.
- Restore use of EditorWindow.set_indentation_params(), was dead code since
Autoindent was merged into EditorWindow. This allows IDLE to conform to the
indentation width of a loaded file. (But it still will not switch to tabs
even if the file uses tabs.) Any change in indent width is local to that
window.
- Add Tabnanny check before Run/F5, not just when Checking module.
- If an extension can't be loaded, print warning and skip it instead of
erroring out.
- Improve error handling when .idlerc can't be created (warn and exit).
- The GUI was hanging if the shell window was closed while a raw_input()
was pending. Restored the quit() of the readline() mainloop().
http://mail.python.org/pipermail/idle-dev/2004-December/002307.html
- The remote procedure call module rpc.py can now access data attributes of
remote registered objects. Changes to these attributes are local, however.
What's New in IDLE 1.1?
=======================
*Release date: 30-NOV-2004*
- On OpenBSD, terminating IDLE with ctrl-c from the command line caused a
stuck subprocess MainThread because only the SocketThread was exiting.
- Saving a Keyset w/o making changes (by using the "Save as New Custom Key Set"
button) caused IDLE to fail on restart (no new keyset was created in
config-keys.cfg). Also true for Theme/highlights. Python Bug 1064535.
- A change to the linecache.py API caused IDLE to exit when an exception was
raised while running without the subprocess (-n switch). Python Bug 1063840.
- When paragraph reformat width was made configurable, a bug was
introduced that caused reformatting of comment blocks to ignore how
far the block was indented, effectively adding the indentation width
to the reformat width. This has been repaired, and the reformat
width is again a bound on the total width of reformatted lines.
- Improve keyboard focus binding, especially in Windows menu. Improve
window raising, especially in the Windows menu and in the debugger.
IDLEfork 763524.
- If user passes a non-existent filename on the commandline, just
open a new file, don't raise a dialog. IDLEfork 854928.
- EditorWindow.py was not finding the .chm help file on Windows. Typo
at Rev 1.54. Python Bug 990954
- checking sys.platform for substring 'win' was breaking IDLE docs on Mac
(darwin). Also, Mac Safari browser requires full file:// URIs. SF 900580.
- Redirect the warning stream to the shell during the ScriptBinding check of
user code and format the warning similarly to an exception for both that
check and for runtime warnings raised in the subprocess.
- CodeContext hint pane visibility state is now persistent across sessions.
The pane no longer appears in the shell window. Added capability to limit
extensions to shell window or editor windows. Noam Raphael addition
to Patch 936169.
- Paragraph reformat width is now a configurable parameter in the
Options GUI.
- New Extension: CodeContext. Provides block structuring hints for code
which has scrolled above an edit window. Patch 936169 Noam Raphael.
- If nulls somehow got into the strings in recent-files.lst
EditorWindow.update_recent_files_list() was failing. Python Bug 931336.
- If the normal background is changed via Configure/Highlighting, it will
update immediately, thanks to the previously mentioned patch by Nigel Rowe.
- Add a highlight theme for builtin keywords. Python Patch 805830 Nigel Rowe
This also fixed IDLEfork bug [ 693418 ] Normal text background color not
refreshed and Python bug [897872 ] Unknown color name on HP-UX
- rpc.py:SocketIO - Large modules were generating large pickles when downloaded
to the execution server. The return of the OK response from the subprocess
initialization was interfering and causing the sending socket to be not
ready. Add an IO ready test to fix this. Moved the polling IO ready test
into pollpacket().
- Fix typo in rpc.py, s/b "pickle.PicklingError" not "pickle.UnpicklingError".
- Added a Tk error dialog to run.py inform the user if the subprocess can't
connect to the user GUI process. Added a timeout to the GUI's listening
socket. Added Tk error dialogs to PyShell.py to announce a failure to bind
the port or connect to the subprocess. Clean up error handling during
connection initiation phase. This is an update of Python Patch 778323.
- Print correct exception even if source file changed since shell was
restarted. IDLEfork Patch 869012 Noam Raphael
- Keybindings with the Shift modifier now work correctly. So do bindings which
use the Space key. Limit unmodified user keybindings to the function keys.
Python Bug 775353, IDLEfork Bugs 755647, 761557
- After an exception, run.py was not setting the exception vector. Noam
Raphael suggested correcting this so pdb's postmortem pm() would work.
IDLEfork Patch 844675
- IDLE now does not fail to save the file anymore if the Tk buffer is not a
Unicode string, yet eol_convention is. Python Bugs 774680, 788378
- IDLE didn't start correctly when Python was installed in "Program Files" on
W2K and XP. Python Bugs 780451, 784183
- config-main.def documentation incorrectly referred to idle- instead of
config- filenames. SF 782759 Also added note about .idlerc location.
What's New in IDLE 1.0?
=======================
*Release date: 29-Jul-2003*
- Added a banner to the shell discussing warnings possibly raised by personal
firewall software. Added same comment to README.txt.
- Calltip error when docstring was None Python Bug 775541
- Updated extend.txt, help.txt, and config-extensions.def to correctly
reflect the current status of the configuration system. Python Bug 768469
- Fixed: Call Tip Trimming May Loop Forever. Python Patch 769142 (Daniels)
- Replaced apply(f, args, kwds) with f(*args, **kwargs) to improve performance
Python Patch 768187
- Break or continue statements outside a loop were causing IDLE crash
Python Bug 767794
- Convert Unicode strings from readline to IOBinding.encoding. Also set
sys.std{in|out|err}.encoding, for both the local and the subprocess case.
SF IDLEfork patch 682347.
- Extend AboutDialog.ViewFile() to support file encodings. Make the CREDITS
file Latin-1.
- Updated the About dialog to reflect re-integration into Python. Provide
buttons to display Python's NEWS, License, and Credits, plus additional
buttons for IDLE's README and NEWS.
- TextViewer() now has a third parameter which allows inserting text into the
viewer instead of reading from a file.
- (Created the .../Lib/idlelib directory in the Python CVS, which is a clone of
IDLEfork modified to install in the Python environment. The code in the
interrupt module has been moved to thread.interrupt_main(). )
- Printing the Shell window was failing if it was not saved first SF 748975
- When using the Search in Files dialog, if the user had a selection
highlighted in his Editor window, insert it into the dialog search field.
- The Python Shell entry was disappearing from the Windows menu.
- Update the Windows file list when a file name change occurs
- Change to File / Open Module: always pop up the dialog, using the current
selection as the default value. This is easier to use habitually.
- Avoided a problem with starting the subprocess when 'localhost' doesn't
resolve to the user's loopback interface. SF 747772
- Fixed an issue with highlighted errors never de-colorizing. SF 747677. Also
improved notification of Tabnanny Token Error.
- File / New will by default save in the directory of the Edit window from
which it was initiated. SF 748973 Guido van Rossum patch.
What's New in IDLEfork 0.9b1?
=============================
*Release date: 02-Jun-2003*
- The current working directory of the execution environment (and shell
following completion of execution) is now that of the module being run.
- Added the delete-exitfunc option to config-main.def. (This option is not
included in the Options dialog.) Setting this to True (the default) will
cause IDLE to not run sys.exitfunc/atexit when the subprocess exits.
- IDLE now preserves the line ending codes when editing a file produced on
a different platform. SF 661759, SF 538584
- Reduced default editor font size to 10 point and increased window height
to provide a better initial impression on Windows.
- Options / Fonts/Tabs / Set Base Editor Font: List box was not highlighting
the default font when first installed on Windows. SF 661676
- Added Autosave feature: when user runs code from edit window, if the file
has been modified IDLE will silently save it if Autosave is enabled. The
option is set in the Options dialog, and the default is to prompt the
user to save the file. SF 661318 Bruce Sherwood patch.
- Improved the RESTART annotation in the shell window when the user restarts
the shell while it is generating output. Also improved annotation when user
repeatedly hammers the Ctrl-F6 restart.
- Allow IDLE to run when not installed and cwd is not the IDLE directory
SF Patch 686254 "Run IDLEfork from any directory without set-up" - Raphael
- When a module is run from an EditorWindow: if its directory is not in
sys.path, prepend it. This allows the module to import other modules in
the same directory. Do the same for a script run from the command line.
- Correctly restart the subprocess if it is running user code and the user
attempts to run some other module or restarts the shell. Do the same if
the link is broken and it is possible to restart the subprocess and re-
connect to the GUI. SF RFE 661321.
- Improved exception reporting when running commands or scripts from the
command line.
- Added a -n command line switch to start IDLE without the subprocess.
Removed the Shell menu when running in that mode. Updated help messages.
- Added a comment to the shell startup header to indicate when IDLE is not
using the subprocess.
- Restore the ability to run without the subprocess. This can be important for
some platforms or configurations. (Running without the subprocess allows the
debugger to trace through parts of IDLE itself, which may or may not be
desirable, depending on your point of view. In addition, the traditional
reload/import tricks must be use if user source code is changed.) This is
helpful for developing IDLE using IDLE, because one instance can be used to
edit the code and a separate instance run to test changes. (Multiple
concurrent IDLE instances with subprocesses is a future feature)
- Improve the error message a user gets when saving a file with non-ASCII
characters and no source encoding is specified. Done by adding a dialog
'EncodingMessage', which contains the line to add in a fixed-font entry
widget, and which has a button to add that line to the file automatically.
Also, add a configuration option 'EditorWindow/encoding', which has three
possible values: none, utf-8, and locale. None is the default: IDLE will show
this dialog when non-ASCII characters are encountered. utf-8 means that files
with non-ASCII characters are saved as utf-8-with-bom. locale means that
files are saved in the locale's encoding; the dialog is only displayed if the
source contains characters outside the locale's charset. SF 710733 - Loewis
- Improved I/O response by tweaking the wait parameter in various
calls to signal.signal().
- Implemented a threaded subprocess which allows interrupting a pass
loop in user code using the 'interrupt' extension. User code runs
in MainThread, while the RPCServer is handled by SockThread. This is
necessary because Windows doesn't support signals.
- Implemented the 'interrupt' extension module, which allows a subthread
to raise a KeyboardInterrupt in the main thread.
- Attempting to save the shell raised an error related to saving
breakpoints, which are not implemented in the shell
- Provide a correct message when 'exit' or 'quit' are entered at the
IDLE command prompt SF 695861
- Eliminate extra blank line in shell output caused by not flushing
stdout when user code ends with an unterminated print. SF 695861
- Moved responsibility for exception formatting (i.e. pruning IDLE internal
calls) out of rpc.py into the client and server.
- Exit IDLE cleanly even when doing subprocess I/O
- Handle subprocess interrupt with an RPC message.
- Restart the subprocess if it terminates itself. (VPython programs do that)
- Support subclassing of exceptions, including in the shell, by moving the
exception formatting to the subprocess.
What's New in IDLEfork 0.9 Alpha 2?
===================================
*Release date: 27-Jan-2003*
- Updated INSTALL.txt to claify use of the python2 rpm.
- Improved formatting in IDLE Help.
- Run menu: Replace "Run Script" with "Run Module".
- Code encountering an unhandled exception under the debugger now shows
the correct traceback, with IDLE internal levels pruned out.
- If an exception occurs entirely in IDLE, don't prune the IDLE internal
modules from the traceback displayed.
- Class Browser and Path Browser now use Alt-Key-2 for vertical zoom.
- IDLE icons will now install correctly even when setup.py is run from the
build directory
- Class Browser now compatible with Python2.3 version of pyclbr.py
- Left cursor move in presence of selected text now moves from left end
of the selection.
- Add Meta keybindings to "IDLE Classic Windows" to handle reversed
Alt/Meta on some Linux distros.
- Change default: IDLE now starts with Python Shell.
- Removed the File Path from the Additional Help Sources scrolled list.
- Add capability to access Additional Help Sources on the web if the
Help File Path begins with //http or www. (Otherwise local path is
validated, as before.)
- Additional Help Sources were not being posted on the Help menu in the
order entered. Implement sorting the list by [HelpFiles] 'option'
number.
- Add Browse button to New Help Source dialog. Arrange to start in
Python/Doc if platform is Windows, otherwise start in current directory.
- Put the Additional Help Sources directly on the Help menu instead of in
an Extra Help cascade menu. Rearrange the Help menu so the Additional
Help Sources come last. Update help.txt appropriately.
- Fix Tk root pop-ups in configSectionNameDialog.py and configDialog.py
- Uniform capitalization in General tab of ConfigDialog, update the doc string.
- Fix bug in ConfigDialog where SaveAllChangedConfig() was unexpectedly
deleting Additional Help Sources from the user's config file.
- Make configHelpSourceEdit OK button the default and bind <Return>
- Fix Tk root pop-ups in configHelpSourceEdit: error dialogs not attached
to parents.
- Use os.startfile() to open both Additional Help and Python Help on the
Windows platform. The application associated with the file type will act as
the viewer. Windows help files (.chm) are now supported via the
Settings/General/Additional Help facility.
- If Python Help files are installed locally on Linux, use them instead of
accessing python.org.
- Make the methods for finding the Python help docs more robust, and make
them work in the installed configuration, also.
- On the Save Before Run dialog, make the OK button the default. One
less mouse action!
- Add a method: EditorWindow.get_geometry() for future use in implementing
window location persistence.
- Removed the "Help/Advice" menu entry. Thanks, David! We'll remember!
- Change the "Classic Windows" theme's paste key to be <ctrl-v>.
- Rearrange the Shell menu to put Stack Viewer entries adjacent.
- Add the ability to restart the subprocess interpreter from the shell window;
add an associated menu entry "Shell/Restart" with binding Control-F6. Update
IDLE help.
- Upon a restart, annotate the shell window with a "restart boundary". Add a
shell window menu "Shell/View Restart" with binding F6 to jump to the most
recent restart boundary.
- Add Shell menu to Python Shell; change "Settings" to "Options".
- Remove incorrect comment in setup.py: IDLEfork is now installed as a package.
- Add INSTALL.txt, HISTORY.txt, NEWS.txt to installed configuration.
- In installer text, fix reference to Visual Python, should be VPython.
Properly credit David Scherer.
- Modified idle, idle.py, idle.pyw to improve exception handling.
What's New in IDLEfork 0.9 Alpha 1?
===================================
*Release date: 31-Dec-2002*
- First release of major new functionality. For further details refer to
Idle-dev and/or the Sourceforge CVS.
- Adapted to the Mac platform.
- Overhauled the IDLE startup options and revised the idle -h help message,
which provides details of command line usage.
- Multiple bug fixes and usability enhancements.
- Introduced the new RPC implementation, which includes a debugger. The output
of user code is to the shell, and the shell may be used to inspect the
environment after the run has finished. (In version 0.8.1 the shell
environment was separate from the environment of the user code.)
- Introduced the configuration GUI and a new About dialog.
- Removed David Scherer's Remote Procedure Call code and replaced with Guido
van Rossum's. GvR code has support for the IDLE debugger and uses the shell
to inspect the environment of code Run from an Edit window. Files removed:
ExecBinding.py, loader.py, protocol.py, Remote.py, spawn.py
--------------------------------------------------------------------
Refer to HISTORY.txt for additional information on earlier releases.
--------------------------------------------------------------------

290
.CondaPkg/env/Lib/idlelib/README.txt vendored Normal file
View File

@@ -0,0 +1,290 @@
README.txt: an index to idlelib files and the IDLE menu.
IDLE is Python's Integrated Development and Learning
Environment. The user documentation is part of the Library Reference and
is available in IDLE by selecting Help => IDLE Help. This README documents
idlelib for IDLE developers and curious users.
IDLELIB FILES lists files alphabetically by category,
with a short description of each.
IDLE MENU show the menu tree, annotated with the module
or module object that implements the corresponding function.
This file is descriptive, not prescriptive, and may have errors
and omissions and lag behind changes in idlelib.
IDLELIB FILES
=============
Implementation files not in IDLE MENU are marked (nim).
Startup
-------
__init__.py # import, does nothing
__main__.py # -m, starts IDLE
idle.bat
idle.py
idle.pyw
Implementation
--------------
autocomplete.py # Complete attribute names or filenames.
autocomplete_w.py # Display completions.
autoexpand.py # Expand word with previous word in file.
browser.py # Create module browser window.
calltip.py # Create calltip text.
calltip_w.py # Display calltip.
codecontext.py # Show compound statement headers otherwise not visible.
colorizer.py # Colorize text (nim).
config.py # Load, fetch, and save configuration (nim).
configdialog.py # Display user configuration dialogs.
config_key.py # Change keybindings.
debugger.py # Debug code run from shell or editor; show window.
debugger_r.py # Debug code run in remote process.
debugobj.py # Define class used in stackviewer.
debugobj_r.py # Communicate objects between processes with rpc (nim).
delegator.py # Define base class for delegators (nim).
dynoption.py # Define mutable OptionMenu widget (nim)
editor.py # Define most of editor and utility functions.
filelist.py # Open files and manage list of open windows (nim).
format.py # Define format menu options.
grep.py # Find all occurrences of pattern in multiple files.
help.py # Display IDLE's html doc.
help_about.py # Display About IDLE dialog.
history.py # Get previous or next user input in shell (nim)
hyperparser.py # Parse code around a given index.
iomenu.py # Open, read, and write files
macosx.py # Help IDLE run on Macs (nim).
mainmenu.py # Define most of IDLE menu.
multicall.py # Wrap tk widget to allow multiple calls per event (nim).
outwin.py # Create window for grep output.
parenmatch.py # Match fenceposts: (), [], and {}.
pathbrowser.py # Create path browser window.
percolator.py # Manage delegator stack (nim).
pyparse.py # Give information on code indentation
pyshell.py # Start IDLE, manage shell, complete editor window
query.py # Query user for information
redirector.py # Intercept widget subcommands (for percolator) (nim).
replace.py # Search and replace pattern in text.
rpc.py # Communicate between idle and user processes (nim).
run.py # Manage user code execution subprocess.
runscript.py # Check and run user code.
scrolledlist.py # Define scrolledlist widget for IDLE (nim).
search.py # Search for pattern in text.
searchbase.py # Define base for search, replace, and grep dialogs.
searchengine.py # Define engine for all 3 search dialogs.
sidebar.py # Define line number and shell prompt sidebars.
squeezer.py # Squeeze long shell output (nim).
stackviewer.py # View stack after exception.
statusbar.py # Define status bar for windows (nim).
tabbedpages.py # Define tabbed pages widget (nim).
textview.py # Define read-only text widget (nim).
tooltip.py # Define popups for calltips, squeezer (nim).
tree.py # Define tree widget, used in browsers (nim).
undo.py # Manage undo stack.
util.py # Define common objects imported elsewhere (nim).
windows.py # Manage window list and define listed top level.
zoomheight.py # Zoom window to full height of screen.
zzdummy.py # Example extension.
Configuration
-------------
config-extensions.def # Defaults for extensions
config-highlight.def # Defaults for colorizing
config-keys.def # Defaults for key bindings
config-main.def # Defaults for font and general tabs
Text
----
CREDITS.txt # not maintained, displayed by About IDLE
HISTORY.txt # NEWS up to July 2001
NEWS.txt # commits, displayed by About IDLE
NEWS2.txt # commits to Python2
README.txt # this file, displayed by About IDLE
TODO.txt # needs review
extend.txt # about writing extensions
help.html # copy of idle.html in docs, displayed by IDLE Help
Subdirectories
--------------
Icons # small image files
idle_test # files for human test and automated unit tests
IDLE MENUS
==========
Top level items and most submenu items are defined in mainmenu.
Extensions add submenu items when active. The names given are
found, quoted, in one of these modules, paired with a '<<pseudoevent>>'.
Each pseudoevent is bound to an event handler. Some event handlers
call another function that does the actual work. The annotations below
are intended to at least give the module where the actual work is done.
'eEW' = editor.EditorWindow
File
New File # eEW.new_callback
Open... # iomenu.open
Open Module # eEw.open_module
Recent Files
Class Browser # eEW.open_class_browser, browser.ClassBrowser
Path Browser # eEW.open_path_browser, pathbrowser
---
Save # iomenu.save
Save As... # iomenu.save_as
Save Copy As... # iomenu.save_a_copy
---
Print Window # iomenu.print_window
---
Close # eEW.close_event
Exit # flist.close_all_callback (bound in eEW)
Edit
Undo # undodelegator
Redo # undodelegator
--- # eEW.right_menu_event
Cut # eEW.cut
Copy # eEW.copy
Paste # eEW.past
Select All # eEW.select_all (+ see eEW.remove_selection)
--- # Next 5 items use searchengine; dialogs use searchbase
Find # eEW.find_event, search.SearchDialog.find
Find Again # eEW.find_again_event, sSD.find_again
Find Selection # eEW.find_selection_event, sSD.find_selection
Find in Files... # eEW.find_in_files_event, grep
Replace... # eEW.replace_event, replace.ReplaceDialog.replace
Go to Line # eEW.goto_line_event
Show Completions # autocomplete extension and autocompleteWidow (&HP)
Expand Word # autoexpand extension
Show call tip # Calltips extension and CalltipWindow (& Hyperparser)
Show surrounding parens # parenmatch (& Hyperparser)
Format (Editor only) [fFR = format.FormatRegion]
Format Paragraph # format.FormatParagraph.format_paragraph_event
Indent Region # fFR.indent_region_event
Dedent Region # fFR.dedent_region_event
Comment Out Reg. # fFR.comment_region_event
Uncomment Region # fFR.uncomment_region_event
Tabify Region # fFR.tabify_region_event
Untabify Region # fFR.untabify_region_event
Toggle Tabs # format.Indents.toggle_tabs_event
New Indent Width # format.Indents.change_indentwidth_event
Strip tailing whitespace # format.rstrip
Zin # zzdummy
Zout # zzdummy
Run (Editor only)
Run Module # runscript.ScriptBinding.run_module_event
Run... Customized # runscript.ScriptBinding.run_custom_event
Check Module # runscript.ScriptBinding.check_module_event
Python Shell # pyshell.Pyshell, pyshell.ModifiedInterpreter
Shell # pyshell
View Last Restart # pyshell.PyShell.view_restart_mark
Restart Shell # pyshell.PyShell.restart_shell
Previous History # history.History.history_prev
Next History # history.History.history_next
Interrupt Execution # pyshell.PyShell.cancel_callback
Debug (Shell only)
Go to File/Line # outwin.OutputWindow.goto_file_line
debugger # debugger, debugger_r, PyShell.toggle_debugger
Stack Viewer # stackviewer, PyShell.open_stack_viewer
Auto-open Stack Viewer # stackviewer
Options
Configure IDLE # eEW.config_dialog, config, configdialog (cd)
(Parts of the dialog)
Buttons # cd.ConfigDialog
Font tab # cd.FontPage, config-main.def
Highlight tab # cd.HighPage, query, config-highlight.def
Keys tab # cd.KeysPage, query, config_key, config_keys.def
Windows tab # cd.WinPage, config_main.def
Shell/Ed tab # cd.ShedPage, config-main.def
Extensions tab # config-extensions.def, corresponding .py files
---
... Code Context # codecontext
... Line Numbers # sidebar
Zoomheight # zoomheight
Window
<open windows> # windows
Help
About IDLE # eEW.about_dialog, help_about.AboutDialog
---
IDLE Help # eEW.help_dialog, help.show_idlehelp
Python Docs # eEW.python_docs
Turtle Demo # eEW.open_turtle_demo
---
<other help sources>
<Context Menu> (right click)
Defined in editor, PyShell.pyshell
Cut
Copy
Paste
---
Go to file/line (shell and output only)
Set Breakpoint (editor only)
Clear Breakpoint (editor only)
Defined in debugger
Go to source line
Show stack frame
<No menu>
Center Insert # eEW.center_insert_event
OTHER TOPICS
============
Generally use PEP 8.
import statements
-----------------
Put imports at the top, unless there is a good reason otherwise.
PEP 8 says to group stdlib, 3rd-party dependencies, and package imports.
For idlelib, the groups are general stdlib, tkinter, and idlelib.
Sort modules within each group, except that tkinter.ttk follows tkinter.
Sort 'from idlelib import mod1' and 'from idlelib.mod2 import object'
together by module, ignoring within module objects.
Put 'import __main__' after other idlelib imports.
Imports only needed for testing are put not at the top but in an
htest function def or "if __name__ == '__main__'" clause.
Within module imports like "from idlelib.mod import class" may cause
circular imports to deadlock. Even without this, circular imports may
require at least one of the imports to be delayed until a function call.
What's New entries
------------------
Repository directory Doc/whatsnew/ has a file 3.n.rst for each 3.n
Python version. For the first entry in each file, add subsection
'IDLE and idlelib', in alphabetical position, to the 'Improved Modules'
section. For the rest of cpython, entries to 3.(n+1).rst begin with
the release of 3.n.0b1. For IDLE, entries for features backported from
'main' to '3.n' during its beta period do not got in 3.(n+1).rst. The
latter usually gets its first entry during the 3.n.0 candidate period
or after the 3.n.0 release.
When, as per PEP 434, feature changes are backported, entries are placed
in the 3.n.rst file *in the main branch* for each Python version n that
gets the backport. (Note: the format of entries have varied between
versions.) Add a line "New in 3.n maintenance releases." before the
first back-ported feature after 3.n.0 is released. Since each older
version file gets a different number of backports, it is easiest to
make a separate PR for each file and label it with the backports
needed.
Github repository and issues
----------------------------
The CPython repository is https://github.com/python/cpython. The
IDLE Issues listing is https://github.com/orgs/python/projects/31.
The main classification is by Topic, based on the IDLE menu. View the
topics list by clicking the [<]] button in the upper right.

210
.CondaPkg/env/Lib/idlelib/TODO.txt vendored Normal file
View File

@@ -0,0 +1,210 @@
Original IDLE todo, much of it now outdated:
============================================
TO DO:
- improve debugger:
- manage breakpoints globally, allow bp deletion, tbreak, cbreak etc.
- real object browser
- help on how to use it (a simple help button will do wonders)
- performance? (updates of large sets of locals are slow)
- better integration of "debug module"
- debugger should be global resource (attached to flist, not to shell)
- fix the stupid bug where you need to step twice
- display class name in stack viewer entries for methods
- suppress tracing through IDLE internals (e.g. print) DONE
- add a button to suppress through a specific module or class or method
- more object inspection to stack viewer, e.g. to view all array items
- insert the initial current directory into sys.path DONE
- default directory attribute for each window instead of only for windows
that have an associated filename
- command expansion from keywords, module contents, other buffers, etc.
- "Recent documents" menu item DONE
- Filter region command
- Optional horizontal scroll bar
- more Emacsisms:
- ^K should cut to buffer
- M-[, M-] to move by paragraphs
- incremental search?
- search should indicate wrap-around in some way
- restructure state sensitive code to avoid testing flags all the time
- persistent user state (e.g. window and cursor positions, bindings)
- make backups when saving
- check file mtimes at various points
- Pluggable interface with RCS/CVS/Perforce/Clearcase
- better help?
- don't open second class browser on same module (nor second path browser)
- unify class and path browsers
- Need to define a standard way whereby one can determine one is running
inside IDLE (needed for Tk mainloop, also handy for $PYTHONSTARTUP)
- Add more utility methods for use by extensions (a la get_selection)
- Way to run command in totally separate interpreter (fork+os.system?) DONE
- Way to find definition of fully-qualified name:
In other words, select "UserDict.UserDict", hit some magic key and
it loads up UserDict.py and finds the first def or class for UserDict.
- need a way to force colorization on/off
- need a way to force auto-indent on/off
Details:
- ^O (on Unix -- open-line) should honor autoindent
- after paste, show end of pasted text
- on Windows, should turn short filename to long filename (not only in argv!)
(shouldn't this be done -- or undone -- by ntpath.normpath?)
- new autoindent after colon even indents when the colon is in a comment!
- sometimes forward slashes in pathname remain
- sometimes star in window name remains in Windows menu
- With unix bindings, ESC by itself is ignored
- Sometimes for no apparent reason a selection from the cursor to the
end of the command buffer appears, which is hard to get rid of
because it stays when you are typing!
- The Line/Col in the status bar can be wrong initially in PyShell DONE
Structural problems:
- too much knowledge in FileList about EditorWindow (for example)
- should add some primitives for accessing the selection etc.
to repeat cumbersome code over and over
======================================================================
Jeff Bauer suggests:
- Open Module doesn't appear to handle hierarchical packages.
- Class browser should also allow hierarchical packages.
- Open and Open Module could benefit from a history, DONE
either command line style, or Microsoft recent-file
style.
- Add a Smalltalk-style inspector (i.e. Tkinspect)
The last suggestion is already a reality, but not yet
integrated into IDLE. I use a module called inspector.py,
that used to be available from python.org(?) It no longer
appears to be in the contributed section, and the source
has no author attribution.
In any case, the code is useful for visually navigating
an object's attributes, including its container hierarchy.
>>> from inspector import Tkinspect
>>> Tkinspect(None, myObject)
Tkinspect could probably be extended and refined to
integrate better into IDLE.
======================================================================
Comparison to PTUI
------------------
+ PTUI's help is better (HTML!)
+ PTUI can attach a shell to any module
+ PTUI has some more I/O commands:
open multiple
append
examine (what's that?)
======================================================================
Notes after trying to run Grail
-------------------------------
- Grail does stuff to sys.path based on sys.argv[0]; you must set
sys.argv[0] to something decent first (it is normally set to the path of
the idle script).
- Grail must be exec'ed in __main__ because that's imported by some
other parts of Grail.
- Grail uses a module called History and so does idle :-(
======================================================================
Robin Friedrich's items:
Things I'd like to see:
- I'd like support for shift-click extending the selection. There's a
bug now that it doesn't work the first time you try it.
- Printing is needed. How hard can that be on Windows? FIRST CUT DONE
- The python-mode trick of autoindenting a line with <tab> is neat and
very handy.
- (someday) a spellchecker for docstrings and comments.
- a pagedown/up command key which moves to next class/def statement (top
level)
- split window capability
- DnD text relocation/copying
Things I don't want to see.
- line numbers... will probably slow things down way too much.
- Please use another icon for the tree browser leaf. The small snake
isn't cutting it.
----------------------------------------------------------------------
- Customizable views (multi-window or multi-pane). (Markus Gritsch)
- Being able to double click (maybe double right click) on a callable
object in the editor which shows the source of the object, if
possible. (Gerrit Holl)
- Hooks into the guts, like in Emacs. (Mike Romberg)
- Sharing the editor with a remote tutor. (Martijn Faassen)
- Multiple views on the same file. (Tony J Ibbs)
- Store breakpoints in a global (per-project) database (GvR); Dirk
Heise adds: save some space-trimmed context and search around when
reopening a file that might have been edited by someone else.
- Capture menu events in extensions without changing the IDLE source.
(Matthias Barmeier)
- Use overlapping panels (a "notebook" in MFC terms I think) for info
that doesn't need to be accessible simultaneously (e.g. HTML source
and output). Use multi-pane windows for info that does need to be
shown together (e.g. class browser and source). (Albert Brandl)
- A project should invisibly track all symbols, for instant search,
replace and cross-ref. Projects should be allowed to span multiple
directories, hosts, etc. Project management files are placed in a
directory you specify. A global mapping between project names and
project directories should exist [not so sure --GvR]. (Tim Peters)
- Merge attr-tips and auto-expand. (Mark Hammond, Tim Peters)
- Python Shell should behave more like a "shell window" as users know
it -- i.e. you can only edit the current command, and the cursor can't
escape from the command area. (Albert Brandl)
- Set X11 class to "idle/Idle", set icon and title to something
beginning with "idle" -- for window manangers. (Randall Hopper)
- Config files editable through a preferences dialog. (me) DONE
- Config files still editable outside the preferences dialog.
(Randall Hopper) DONE
- When you're editing a command in PyShell, and there are only blank
lines below the cursor, hitting Return should ignore or delete those
blank lines rather than deciding you're not on the last line. (me)
- Run command (F5 c.s.) should be more like Pythonwin's Run -- a
dialog with options to give command line arguments, run the debugger,
etc. (me)
- Shouldn't be able to delete part of the prompt (or any text before
it) in the PyShell. (Martijn Faassen) DONE
- Emacs style auto-fill (also smart about comments and strings).
(Jeremy Hylton)
- Output of Run Script should go to a separate output window, not to
the shell window. Output of separate runs should all go to the same
window but clearly delimited. (David Scherer) REJECT FIRST, LATTER DONE
- GUI form designer to kick VB's butt. (Robert Geiger) THAT'S NOT IDLE
- Printing! Possibly via generation of PDF files which the user must
then send to the printer separately. (Dinu Gherman) FIRST CUT

10
.CondaPkg/env/Lib/idlelib/__init__.py vendored Normal file
View File

@@ -0,0 +1,10 @@
"""The idlelib package implements the Idle application.
Idle includes an interactive shell and editor.
Starting with Python 3.6, IDLE requires tcl/tk 8.5 or later.
Use the files named idle.* to start Idle.
The other files are private implementations. Their details are subject to
change. See PEP 434 for more. Import them at your own risk.
"""
testing = False # Set True by test.test_idle.

8
.CondaPkg/env/Lib/idlelib/__main__.py vendored Normal file
View File

@@ -0,0 +1,8 @@
"""
IDLE main entry point
Run IDLE as python -m idlelib
"""
import idlelib.pyshell
idlelib.pyshell.main()
# This file does not work for 2.7; See issue 24212.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,228 @@
"""Complete either attribute names or file names.
Either on demand or after a user-selected delay after a key character,
pop up a list of candidates.
"""
import __main__
import keyword
import os
import string
import sys
# Modified keyword list is used in fetch_completions.
completion_kwds = [s for s in keyword.kwlist
if s not in {'True', 'False', 'None'}] # In builtins.
completion_kwds.extend(('match', 'case')) # Context keywords.
completion_kwds.sort()
# Two types of completions; defined here for autocomplete_w import below.
ATTRS, FILES = 0, 1
from idlelib import autocomplete_w
from idlelib.config import idleConf
from idlelib.hyperparser import HyperParser
# Tuples passed to open_completions.
# EvalFunc, Complete, WantWin, Mode
FORCE = True, False, True, None # Control-Space.
TAB = False, True, True, None # Tab.
TRY_A = False, False, False, ATTRS # '.' for attributes.
TRY_F = False, False, False, FILES # '/' in quotes for file name.
# This string includes all chars that may be in an identifier.
# TODO Update this here and elsewhere.
ID_CHARS = string.ascii_letters + string.digits + "_"
SEPS = f"{os.sep}{os.altsep if os.altsep else ''}"
TRIGGERS = f".{SEPS}"
class AutoComplete:
def __init__(self, editwin=None, tags=None):
self.editwin = editwin
if editwin is not None: # not in subprocess or no-gui test
self.text = editwin.text
self.tags = tags
self.autocompletewindow = None
# id of delayed call, and the index of the text insert when
# the delayed call was issued. If _delayed_completion_id is
# None, there is no delayed call.
self._delayed_completion_id = None
self._delayed_completion_index = None
@classmethod
def reload(cls):
cls.popupwait = idleConf.GetOption(
"extensions", "AutoComplete", "popupwait", type="int", default=0)
def _make_autocomplete_window(self): # Makes mocking easier.
return autocomplete_w.AutoCompleteWindow(self.text, tags=self.tags)
def _remove_autocomplete_window(self, event=None):
if self.autocompletewindow:
self.autocompletewindow.hide_window()
self.autocompletewindow = None
def force_open_completions_event(self, event):
"(^space) Open completion list, even if a function call is needed."
self.open_completions(FORCE)
return "break"
def autocomplete_event(self, event):
"(tab) Complete word or open list if multiple options."
if hasattr(event, "mc_state") and event.mc_state or\
not self.text.get("insert linestart", "insert").strip():
# A modifier was pressed along with the tab or
# there is only previous whitespace on this line, so tab.
return None
if self.autocompletewindow and self.autocompletewindow.is_active():
self.autocompletewindow.complete()
return "break"
else:
opened = self.open_completions(TAB)
return "break" if opened else None
def try_open_completions_event(self, event=None):
"(./) Open completion list after pause with no movement."
lastchar = self.text.get("insert-1c")
if lastchar in TRIGGERS:
args = TRY_A if lastchar == "." else TRY_F
self._delayed_completion_index = self.text.index("insert")
if self._delayed_completion_id is not None:
self.text.after_cancel(self._delayed_completion_id)
self._delayed_completion_id = self.text.after(
self.popupwait, self._delayed_open_completions, args)
def _delayed_open_completions(self, args):
"Call open_completions if index unchanged."
self._delayed_completion_id = None
if self.text.index("insert") == self._delayed_completion_index:
self.open_completions(args)
def open_completions(self, args):
"""Find the completions and create the AutoCompleteWindow.
Return True if successful (no syntax error or so found).
If complete is True, then if there's nothing to complete and no
start of completion, won't open completions and return False.
If mode is given, will open a completion list only in this mode.
"""
evalfuncs, complete, wantwin, mode = args
# Cancel another delayed call, if it exists.
if self._delayed_completion_id is not None:
self.text.after_cancel(self._delayed_completion_id)
self._delayed_completion_id = None
hp = HyperParser(self.editwin, "insert")
curline = self.text.get("insert linestart", "insert")
i = j = len(curline)
if hp.is_in_string() and (not mode or mode==FILES):
# Find the beginning of the string.
# fetch_completions will look at the file system to determine
# whether the string value constitutes an actual file name
# XXX could consider raw strings here and unescape the string
# value if it's not raw.
self._remove_autocomplete_window()
mode = FILES
# Find last separator or string start
while i and curline[i-1] not in "'\"" + SEPS:
i -= 1
comp_start = curline[i:j]
j = i
# Find string start
while i and curline[i-1] not in "'\"":
i -= 1
comp_what = curline[i:j]
elif hp.is_in_code() and (not mode or mode==ATTRS):
self._remove_autocomplete_window()
mode = ATTRS
while i and (curline[i-1] in ID_CHARS or ord(curline[i-1]) > 127):
i -= 1
comp_start = curline[i:j]
if i and curline[i-1] == '.': # Need object with attributes.
hp.set_index("insert-%dc" % (len(curline)-(i-1)))
comp_what = hp.get_expression()
if (not comp_what or
(not evalfuncs and comp_what.find('(') != -1)):
return None
else:
comp_what = ""
else:
return None
if complete and not comp_what and not comp_start:
return None
comp_lists = self.fetch_completions(comp_what, mode)
if not comp_lists[0]:
return None
self.autocompletewindow = self._make_autocomplete_window()
return not self.autocompletewindow.show_window(
comp_lists, "insert-%dc" % len(comp_start),
complete, mode, wantwin)
def fetch_completions(self, what, mode):
"""Return a pair of lists of completions for something. The first list
is a sublist of the second. Both are sorted.
If there is a Python subprocess, get the comp. list there. Otherwise,
either fetch_completions() is running in the subprocess itself or it
was called in an IDLE EditorWindow before any script had been run.
The subprocess environment is that of the most recently run script. If
two unrelated modules are being edited some calltips in the current
module may be inoperative if the module was not the last to run.
"""
try:
rpcclt = self.editwin.flist.pyshell.interp.rpcclt
except:
rpcclt = None
if rpcclt:
return rpcclt.remotecall("exec", "get_the_completion_list",
(what, mode), {})
else:
if mode == ATTRS:
if what == "": # Main module names.
namespace = {**__main__.__builtins__.__dict__,
**__main__.__dict__}
bigl = eval("dir()", namespace)
bigl.extend(completion_kwds)
bigl.sort()
if "__all__" in bigl:
smalll = sorted(eval("__all__", namespace))
else:
smalll = [s for s in bigl if s[:1] != '_']
else:
try:
entity = self.get_entity(what)
bigl = dir(entity)
bigl.sort()
if "__all__" in bigl:
smalll = sorted(entity.__all__)
else:
smalll = [s for s in bigl if s[:1] != '_']
except:
return [], []
elif mode == FILES:
if what == "":
what = "."
try:
expandedpath = os.path.expanduser(what)
bigl = os.listdir(expandedpath)
bigl.sort()
smalll = [s for s in bigl if s[:1] != '.']
except OSError:
return [], []
if not smalll:
smalll = bigl
return smalll, bigl
def get_entity(self, name):
"Lookup name in a namespace spanning sys.modules and __main.dict__."
return eval(name, {**sys.modules, **__main__.__dict__})
AutoComplete.reload()
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_autocomplete', verbosity=2)

View File

@@ -0,0 +1,498 @@
"""
An auto-completion window for IDLE, used by the autocomplete extension
"""
import platform
from tkinter import *
from tkinter.ttk import Scrollbar
from idlelib.autocomplete import FILES, ATTRS
from idlelib.multicall import MC_SHIFT
HIDE_VIRTUAL_EVENT_NAME = "<<autocompletewindow-hide>>"
HIDE_FOCUS_OUT_SEQUENCE = "<FocusOut>"
HIDE_SEQUENCES = (HIDE_FOCUS_OUT_SEQUENCE, "<ButtonPress>")
KEYPRESS_VIRTUAL_EVENT_NAME = "<<autocompletewindow-keypress>>"
# We need to bind event beyond <Key> so that the function will be called
# before the default specific IDLE function
KEYPRESS_SEQUENCES = ("<Key>", "<Key-BackSpace>", "<Key-Return>", "<Key-Tab>",
"<Key-Up>", "<Key-Down>", "<Key-Home>", "<Key-End>",
"<Key-Prior>", "<Key-Next>", "<Key-Escape>")
KEYRELEASE_VIRTUAL_EVENT_NAME = "<<autocompletewindow-keyrelease>>"
KEYRELEASE_SEQUENCE = "<KeyRelease>"
LISTUPDATE_SEQUENCE = "<B1-ButtonRelease>"
WINCONFIG_SEQUENCE = "<Configure>"
DOUBLECLICK_SEQUENCE = "<B1-Double-ButtonRelease>"
class AutoCompleteWindow:
def __init__(self, widget, tags):
# The widget (Text) on which we place the AutoCompleteWindow
self.widget = widget
# Tags to mark inserted text with
self.tags = tags
# The widgets we create
self.autocompletewindow = self.listbox = self.scrollbar = None
# The default foreground and background of a selection. Saved because
# they are changed to the regular colors of list items when the
# completion start is not a prefix of the selected completion
self.origselforeground = self.origselbackground = None
# The list of completions
self.completions = None
# A list with more completions, or None
self.morecompletions = None
# The completion mode, either autocomplete.ATTRS or .FILES.
self.mode = None
# The current completion start, on the text box (a string)
self.start = None
# The index of the start of the completion
self.startindex = None
# The last typed start, used so that when the selection changes,
# the new start will be as close as possible to the last typed one.
self.lasttypedstart = None
# Do we have an indication that the user wants the completion window
# (for example, he clicked the list)
self.userwantswindow = None
# event ids
self.hideid = self.keypressid = self.listupdateid = \
self.winconfigid = self.keyreleaseid = self.doubleclickid = None
# Flag set if last keypress was a tab
self.lastkey_was_tab = False
# Flag set to avoid recursive <Configure> callback invocations.
self.is_configuring = False
def _change_start(self, newstart):
min_len = min(len(self.start), len(newstart))
i = 0
while i < min_len and self.start[i] == newstart[i]:
i += 1
if i < len(self.start):
self.widget.delete("%s+%dc" % (self.startindex, i),
"%s+%dc" % (self.startindex, len(self.start)))
if i < len(newstart):
self.widget.insert("%s+%dc" % (self.startindex, i),
newstart[i:],
self.tags)
self.start = newstart
def _binary_search(self, s):
"""Find the first index in self.completions where completions[i] is
greater or equal to s, or the last index if there is no such.
"""
i = 0; j = len(self.completions)
while j > i:
m = (i + j) // 2
if self.completions[m] >= s:
j = m
else:
i = m + 1
return min(i, len(self.completions)-1)
def _complete_string(self, s):
"""Assuming that s is the prefix of a string in self.completions,
return the longest string which is a prefix of all the strings which
s is a prefix of them. If s is not a prefix of a string, return s.
"""
first = self._binary_search(s)
if self.completions[first][:len(s)] != s:
# There is not even one completion which s is a prefix of.
return s
# Find the end of the range of completions where s is a prefix of.
i = first + 1
j = len(self.completions)
while j > i:
m = (i + j) // 2
if self.completions[m][:len(s)] != s:
j = m
else:
i = m + 1
last = i-1
if first == last: # only one possible completion
return self.completions[first]
# We should return the maximum prefix of first and last
first_comp = self.completions[first]
last_comp = self.completions[last]
min_len = min(len(first_comp), len(last_comp))
i = len(s)
while i < min_len and first_comp[i] == last_comp[i]:
i += 1
return first_comp[:i]
def _selection_changed(self):
"""Call when the selection of the Listbox has changed.
Updates the Listbox display and calls _change_start.
"""
cursel = int(self.listbox.curselection()[0])
self.listbox.see(cursel)
lts = self.lasttypedstart
selstart = self.completions[cursel]
if self._binary_search(lts) == cursel:
newstart = lts
else:
min_len = min(len(lts), len(selstart))
i = 0
while i < min_len and lts[i] == selstart[i]:
i += 1
newstart = selstart[:i]
self._change_start(newstart)
if self.completions[cursel][:len(self.start)] == self.start:
# start is a prefix of the selected completion
self.listbox.configure(selectbackground=self.origselbackground,
selectforeground=self.origselforeground)
else:
self.listbox.configure(selectbackground=self.listbox.cget("bg"),
selectforeground=self.listbox.cget("fg"))
# If there are more completions, show them, and call me again.
if self.morecompletions:
self.completions = self.morecompletions
self.morecompletions = None
self.listbox.delete(0, END)
for item in self.completions:
self.listbox.insert(END, item)
self.listbox.select_set(self._binary_search(self.start))
self._selection_changed()
def show_window(self, comp_lists, index, complete, mode, userWantsWin):
"""Show the autocomplete list, bind events.
If complete is True, complete the text, and if there is exactly
one matching completion, don't open a list.
"""
# Handle the start we already have
self.completions, self.morecompletions = comp_lists
self.mode = mode
self.startindex = self.widget.index(index)
self.start = self.widget.get(self.startindex, "insert")
if complete:
completed = self._complete_string(self.start)
start = self.start
self._change_start(completed)
i = self._binary_search(completed)
if self.completions[i] == completed and \
(i == len(self.completions)-1 or
self.completions[i+1][:len(completed)] != completed):
# There is exactly one matching completion
return completed == start
self.userwantswindow = userWantsWin
self.lasttypedstart = self.start
self.autocompletewindow = acw = Toplevel(self.widget)
acw.withdraw()
acw.wm_overrideredirect(1)
try:
# Prevent grabbing focus on macOS.
acw.tk.call("::tk::unsupported::MacWindowStyle", "style", acw._w,
"help", "noActivates")
except TclError:
pass
self.scrollbar = scrollbar = Scrollbar(acw, orient=VERTICAL)
self.listbox = listbox = Listbox(acw, yscrollcommand=scrollbar.set,
exportselection=False)
for item in self.completions:
listbox.insert(END, item)
self.origselforeground = listbox.cget("selectforeground")
self.origselbackground = listbox.cget("selectbackground")
scrollbar.config(command=listbox.yview)
scrollbar.pack(side=RIGHT, fill=Y)
listbox.pack(side=LEFT, fill=BOTH, expand=True)
#acw.update_idletasks() # Need for tk8.6.8 on macOS: #40128.
acw.lift() # work around bug in Tk 8.5.18+ (issue #24570)
# Initialize the listbox selection
self.listbox.select_set(self._binary_search(self.start))
self._selection_changed()
# bind events
self.hideaid = acw.bind(HIDE_VIRTUAL_EVENT_NAME, self.hide_event)
self.hidewid = self.widget.bind(HIDE_VIRTUAL_EVENT_NAME, self.hide_event)
acw.event_add(HIDE_VIRTUAL_EVENT_NAME, HIDE_FOCUS_OUT_SEQUENCE)
for seq in HIDE_SEQUENCES:
self.widget.event_add(HIDE_VIRTUAL_EVENT_NAME, seq)
self.keypressid = self.widget.bind(KEYPRESS_VIRTUAL_EVENT_NAME,
self.keypress_event)
for seq in KEYPRESS_SEQUENCES:
self.widget.event_add(KEYPRESS_VIRTUAL_EVENT_NAME, seq)
self.keyreleaseid = self.widget.bind(KEYRELEASE_VIRTUAL_EVENT_NAME,
self.keyrelease_event)
self.widget.event_add(KEYRELEASE_VIRTUAL_EVENT_NAME,KEYRELEASE_SEQUENCE)
self.listupdateid = listbox.bind(LISTUPDATE_SEQUENCE,
self.listselect_event)
self.is_configuring = False
self.winconfigid = acw.bind(WINCONFIG_SEQUENCE, self.winconfig_event)
self.doubleclickid = listbox.bind(DOUBLECLICK_SEQUENCE,
self.doubleclick_event)
return None
def winconfig_event(self, event):
if self.is_configuring:
# Avoid running on recursive <Configure> callback invocations.
return
self.is_configuring = True
if not self.is_active():
return
# Since the <Configure> event may occur after the completion window is gone,
# catch potential TclError exceptions when accessing acw. See: bpo-41611.
try:
# Position the completion list window
text = self.widget
text.see(self.startindex)
x, y, cx, cy = text.bbox(self.startindex)
acw = self.autocompletewindow
if platform.system().startswith('Windows'):
# On Windows an update() call is needed for the completion
# list window to be created, so that we can fetch its width
# and height. However, this is not needed on other platforms
# (tested on Ubuntu and macOS) but at one point began
# causing freezes on macOS. See issues 37849 and 41611.
acw.update()
acw_width, acw_height = acw.winfo_width(), acw.winfo_height()
text_width, text_height = text.winfo_width(), text.winfo_height()
new_x = text.winfo_rootx() + min(x, max(0, text_width - acw_width))
new_y = text.winfo_rooty() + y
if (text_height - (y + cy) >= acw_height # enough height below
or y < acw_height): # not enough height above
# place acw below current line
new_y += cy
else:
# place acw above current line
new_y -= acw_height
acw.wm_geometry("+%d+%d" % (new_x, new_y))
acw.deiconify()
acw.update_idletasks()
except TclError:
pass
if platform.system().startswith('Windows'):
# See issue 15786. When on Windows platform, Tk will misbehave
# to call winconfig_event multiple times, we need to prevent this,
# otherwise mouse button double click will not be able to used.
try:
acw.unbind(WINCONFIG_SEQUENCE, self.winconfigid)
except TclError:
pass
self.winconfigid = None
self.is_configuring = False
def _hide_event_check(self):
if not self.autocompletewindow:
return
try:
if not self.autocompletewindow.focus_get():
self.hide_window()
except KeyError:
# See issue 734176, when user click on menu, acw.focus_get()
# will get KeyError.
self.hide_window()
def hide_event(self, event):
# Hide autocomplete list if it exists and does not have focus or
# mouse click on widget / text area.
if self.is_active():
if event.type == EventType.FocusOut:
# On Windows platform, it will need to delay the check for
# acw.focus_get() when click on acw, otherwise it will return
# None and close the window
self.widget.after(1, self._hide_event_check)
elif event.type == EventType.ButtonPress:
# ButtonPress event only bind to self.widget
self.hide_window()
def listselect_event(self, event):
if self.is_active():
self.userwantswindow = True
cursel = int(self.listbox.curselection()[0])
self._change_start(self.completions[cursel])
def doubleclick_event(self, event):
# Put the selected completion in the text, and close the list
cursel = int(self.listbox.curselection()[0])
self._change_start(self.completions[cursel])
self.hide_window()
def keypress_event(self, event):
if not self.is_active():
return None
keysym = event.keysym
if hasattr(event, "mc_state"):
state = event.mc_state
else:
state = 0
if keysym != "Tab":
self.lastkey_was_tab = False
if (len(keysym) == 1 or keysym in ("underscore", "BackSpace")
or (self.mode == FILES and keysym in
("period", "minus"))) \
and not (state & ~MC_SHIFT):
# Normal editing of text
if len(keysym) == 1:
self._change_start(self.start + keysym)
elif keysym == "underscore":
self._change_start(self.start + '_')
elif keysym == "period":
self._change_start(self.start + '.')
elif keysym == "minus":
self._change_start(self.start + '-')
else:
# keysym == "BackSpace"
if len(self.start) == 0:
self.hide_window()
return None
self._change_start(self.start[:-1])
self.lasttypedstart = self.start
self.listbox.select_clear(0, int(self.listbox.curselection()[0]))
self.listbox.select_set(self._binary_search(self.start))
self._selection_changed()
return "break"
elif keysym == "Return":
self.complete()
self.hide_window()
return 'break'
elif (self.mode == ATTRS and keysym in
("period", "space", "parenleft", "parenright", "bracketleft",
"bracketright")) or \
(self.mode == FILES and keysym in
("slash", "backslash", "quotedbl", "apostrophe")) \
and not (state & ~MC_SHIFT):
# If start is a prefix of the selection, but is not '' when
# completing file names, put the whole
# selected completion. Anyway, close the list.
cursel = int(self.listbox.curselection()[0])
if self.completions[cursel][:len(self.start)] == self.start \
and (self.mode == ATTRS or self.start):
self._change_start(self.completions[cursel])
self.hide_window()
return None
elif keysym in ("Home", "End", "Prior", "Next", "Up", "Down") and \
not state:
# Move the selection in the listbox
self.userwantswindow = True
cursel = int(self.listbox.curselection()[0])
if keysym == "Home":
newsel = 0
elif keysym == "End":
newsel = len(self.completions)-1
elif keysym in ("Prior", "Next"):
jump = self.listbox.nearest(self.listbox.winfo_height()) - \
self.listbox.nearest(0)
if keysym == "Prior":
newsel = max(0, cursel-jump)
else:
assert keysym == "Next"
newsel = min(len(self.completions)-1, cursel+jump)
elif keysym == "Up":
newsel = max(0, cursel-1)
else:
assert keysym == "Down"
newsel = min(len(self.completions)-1, cursel+1)
self.listbox.select_clear(cursel)
self.listbox.select_set(newsel)
self._selection_changed()
self._change_start(self.completions[newsel])
return "break"
elif (keysym == "Tab" and not state):
if self.lastkey_was_tab:
# two tabs in a row; insert current selection and close acw
cursel = int(self.listbox.curselection()[0])
self._change_start(self.completions[cursel])
self.hide_window()
return "break"
else:
# first tab; let AutoComplete handle the completion
self.userwantswindow = True
self.lastkey_was_tab = True
return None
elif any(s in keysym for s in ("Shift", "Control", "Alt",
"Meta", "Command", "Option")):
# A modifier key, so ignore
return None
elif event.char and event.char >= ' ':
# Regular character with a non-length-1 keycode
self._change_start(self.start + event.char)
self.lasttypedstart = self.start
self.listbox.select_clear(0, int(self.listbox.curselection()[0]))
self.listbox.select_set(self._binary_search(self.start))
self._selection_changed()
return "break"
else:
# Unknown event, close the window and let it through.
self.hide_window()
return None
def keyrelease_event(self, event):
if not self.is_active():
return
if self.widget.index("insert") != \
self.widget.index("%s+%dc" % (self.startindex, len(self.start))):
# If we didn't catch an event which moved the insert, close window
self.hide_window()
def is_active(self):
return self.autocompletewindow is not None
def complete(self):
self._change_start(self._complete_string(self.start))
# The selection doesn't change.
def hide_window(self):
if not self.is_active():
return
# unbind events
self.autocompletewindow.event_delete(HIDE_VIRTUAL_EVENT_NAME,
HIDE_FOCUS_OUT_SEQUENCE)
for seq in HIDE_SEQUENCES:
self.widget.event_delete(HIDE_VIRTUAL_EVENT_NAME, seq)
self.autocompletewindow.unbind(HIDE_VIRTUAL_EVENT_NAME, self.hideaid)
self.widget.unbind(HIDE_VIRTUAL_EVENT_NAME, self.hidewid)
self.hideaid = None
self.hidewid = None
for seq in KEYPRESS_SEQUENCES:
self.widget.event_delete(KEYPRESS_VIRTUAL_EVENT_NAME, seq)
self.widget.unbind(KEYPRESS_VIRTUAL_EVENT_NAME, self.keypressid)
self.keypressid = None
self.widget.event_delete(KEYRELEASE_VIRTUAL_EVENT_NAME,
KEYRELEASE_SEQUENCE)
self.widget.unbind(KEYRELEASE_VIRTUAL_EVENT_NAME, self.keyreleaseid)
self.keyreleaseid = None
self.listbox.unbind(LISTUPDATE_SEQUENCE, self.listupdateid)
self.listupdateid = None
if self.winconfigid:
self.autocompletewindow.unbind(WINCONFIG_SEQUENCE, self.winconfigid)
self.winconfigid = None
# Re-focusOn frame.text (See issue #15786)
self.widget.focus_set()
# destroy widgets
self.scrollbar.destroy()
self.scrollbar = None
self.listbox.destroy()
self.listbox = None
self.autocompletewindow.destroy()
self.autocompletewindow = None
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_autocomplete_w', verbosity=2, exit=False)
# TODO: autocomplete/w htest here

96
.CondaPkg/env/Lib/idlelib/autoexpand.py vendored Normal file
View File

@@ -0,0 +1,96 @@
'''Complete the current word before the cursor with words in the editor.
Each menu selection or shortcut key selection replaces the word with a
different word with the same prefix. The search for matches begins
before the target and moves toward the top of the editor. It then starts
after the cursor and moves down. It then returns to the original word and
the cycle starts again.
Changing the current text line or leaving the cursor in a different
place before requesting the next selection causes AutoExpand to reset
its state.
There is only one instance of Autoexpand.
'''
import re
import string
class AutoExpand:
wordchars = string.ascii_letters + string.digits + "_"
def __init__(self, editwin):
self.text = editwin.text
self.bell = self.text.bell
self.state = None
def expand_word_event(self, event):
"Replace the current word with the next expansion."
curinsert = self.text.index("insert")
curline = self.text.get("insert linestart", "insert lineend")
if not self.state:
words = self.getwords()
index = 0
else:
words, index, insert, line = self.state
if insert != curinsert or line != curline:
words = self.getwords()
index = 0
if not words:
self.bell()
return "break"
word = self.getprevword()
self.text.delete("insert - %d chars" % len(word), "insert")
newword = words[index]
index = (index + 1) % len(words)
if index == 0:
self.bell() # Warn we cycled around
self.text.insert("insert", newword)
curinsert = self.text.index("insert")
curline = self.text.get("insert linestart", "insert lineend")
self.state = words, index, curinsert, curline
return "break"
def getwords(self):
"Return a list of words that match the prefix before the cursor."
word = self.getprevword()
if not word:
return []
before = self.text.get("1.0", "insert wordstart")
wbefore = re.findall(r"\b" + word + r"\w+\b", before)
del before
after = self.text.get("insert wordend", "end")
wafter = re.findall(r"\b" + word + r"\w+\b", after)
del after
if not wbefore and not wafter:
return []
words = []
dict = {}
# search backwards through words before
wbefore.reverse()
for w in wbefore:
if dict.get(w):
continue
words.append(w)
dict[w] = w
# search onwards through words after
for w in wafter:
if dict.get(w):
continue
words.append(w)
dict[w] = w
words.append(word)
return words
def getprevword(self):
"Return the word prefix before the cursor."
line = self.text.get("insert linestart", "insert")
i = len(line)
while i > 0 and line[i-1] in self.wordchars:
i = i-1
return line[i:]
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_autoexpand', verbosity=2)

258
.CondaPkg/env/Lib/idlelib/browser.py vendored Normal file
View File

@@ -0,0 +1,258 @@
"""Module browser.
XXX TO DO:
- reparse when source changed (maybe just a button would be OK?)
(or recheck on window popup)
- add popup menu with more options (e.g. doc strings, base classes, imports)
- add base classes to class browser tree
"""
import os
import pyclbr
import sys
from idlelib.config import idleConf
from idlelib import pyshell
from idlelib.tree import TreeNode, TreeItem, ScrolledCanvas
from idlelib.util import py_extensions
from idlelib.window import ListedToplevel
file_open = None # Method...Item and Class...Item use this.
# Normally pyshell.flist.open, but there is no pyshell.flist for htest.
# The browser depends on pyclbr and importlib which do not support .pyi files.
browseable_extension_blocklist = ('.pyi',)
def is_browseable_extension(path):
_, ext = os.path.splitext(path)
ext = os.path.normcase(ext)
return ext in py_extensions and ext not in browseable_extension_blocklist
def transform_children(child_dict, modname=None):
"""Transform a child dictionary to an ordered sequence of objects.
The dictionary maps names to pyclbr information objects.
Filter out imported objects.
Augment class names with bases.
The insertion order of the dictionary is assumed to have been in line
number order, so sorting is not necessary.
The current tree only calls this once per child_dict as it saves
TreeItems once created. A future tree and tests might violate this,
so a check prevents multiple in-place augmentations.
"""
obs = [] # Use list since values should already be sorted.
for key, obj in child_dict.items():
if modname is None or obj.module == modname:
if hasattr(obj, 'super') and obj.super and obj.name == key:
# If obj.name != key, it has already been suffixed.
supers = []
for sup in obj.super:
if isinstance(sup, str):
sname = sup
else:
sname = sup.name
if sup.module != obj.module:
sname = f'{sup.module}.{sname}'
supers.append(sname)
obj.name += '({})'.format(', '.join(supers))
obs.append(obj)
return obs
class ModuleBrowser:
"""Browse module classes and functions in IDLE.
"""
# This class is also the base class for pathbrowser.PathBrowser.
# Init and close are inherited, other methods are overridden.
# PathBrowser.__init__ does not call __init__ below.
def __init__(self, master, path, *, _htest=False, _utest=False):
"""Create a window for browsing a module's structure.
Args:
master: parent for widgets.
path: full path of file to browse.
_htest - bool; change box location when running htest.
-utest - bool; suppress contents when running unittest.
Global variables:
file_open: Function used for opening a file.
Instance variables:
name: Module name.
file: Full path and module with supported extension.
Used in creating ModuleBrowserTreeItem as the rootnode for
the tree and subsequently in the children.
"""
self.master = master
self.path = path
self._htest = _htest
self._utest = _utest
self.init()
def close(self, event=None):
"Dismiss the window and the tree nodes."
self.top.destroy()
self.node.destroy()
def init(self):
"Create browser tkinter widgets, including the tree."
global file_open
root = self.master
flist = (pyshell.flist if not (self._htest or self._utest)
else pyshell.PyShellFileList(root))
file_open = flist.open
pyclbr._modules.clear()
# create top
self.top = top = ListedToplevel(root)
top.protocol("WM_DELETE_WINDOW", self.close)
top.bind("<Escape>", self.close)
if self._htest: # place dialog below parent if running htest
top.geometry("+%d+%d" %
(root.winfo_rootx(), root.winfo_rooty() + 200))
self.settitle()
top.focus_set()
# create scrolled canvas
theme = idleConf.CurrentTheme()
background = idleConf.GetHighlight(theme, 'normal')['background']
sc = ScrolledCanvas(top, bg=background, highlightthickness=0,
takefocus=1)
sc.frame.pack(expand=1, fill="both")
item = self.rootnode()
self.node = node = TreeNode(sc.canvas, None, item)
if not self._utest:
node.update()
node.expand()
def settitle(self):
"Set the window title."
self.top.wm_title("Module Browser - " + os.path.basename(self.path))
self.top.wm_iconname("Module Browser")
def rootnode(self):
"Return a ModuleBrowserTreeItem as the root of the tree."
return ModuleBrowserTreeItem(self.path)
class ModuleBrowserTreeItem(TreeItem):
"""Browser tree for Python module.
Uses TreeItem as the basis for the structure of the tree.
Used by both browsers.
"""
def __init__(self, file):
"""Create a TreeItem for the file.
Args:
file: Full path and module name.
"""
self.file = file
def GetText(self):
"Return the module name as the text string to display."
return os.path.basename(self.file)
def GetIconName(self):
"Return the name of the icon to display."
return "python"
def GetSubList(self):
"Return ChildBrowserTreeItems for children."
return [ChildBrowserTreeItem(obj) for obj in self.listchildren()]
def OnDoubleClick(self):
"Open a module in an editor window when double clicked."
if not is_browseable_extension(self.file):
return
if not os.path.exists(self.file):
return
file_open(self.file)
def IsExpandable(self):
"Return True if Python file."
return is_browseable_extension(self.file)
def listchildren(self):
"Return sequenced classes and functions in the module."
if not is_browseable_extension(self.file):
return []
dir, base = os.path.split(self.file)
name, _ = os.path.splitext(base)
try:
tree = pyclbr.readmodule_ex(name, [dir] + sys.path)
except ImportError:
return []
return transform_children(tree, name)
class ChildBrowserTreeItem(TreeItem):
"""Browser tree for child nodes within the module.
Uses TreeItem as the basis for the structure of the tree.
"""
def __init__(self, obj):
"Create a TreeItem for a pyclbr class/function object."
self.obj = obj
self.name = obj.name
self.isfunction = isinstance(obj, pyclbr.Function)
def GetText(self):
"Return the name of the function/class to display."
name = self.name
if self.isfunction:
return "def " + name + "(...)"
else:
return "class " + name
def GetIconName(self):
"Return the name of the icon to display."
if self.isfunction:
return "python"
else:
return "folder"
def IsExpandable(self):
"Return True if self.obj has nested objects."
return self.obj.children != {}
def GetSubList(self):
"Return ChildBrowserTreeItems for children."
return [ChildBrowserTreeItem(obj)
for obj in transform_children(self.obj.children)]
def OnDoubleClick(self):
"Open module with file_open and position to lineno."
try:
edit = file_open(self.obj.file)
edit.gotoline(self.obj.lineno)
except (OSError, AttributeError):
pass
def _module_browser(parent): # htest #
if len(sys.argv) > 1: # If pass file on command line.
file = sys.argv[1]
else:
file = __file__
# Add nested objects for htest.
class Nested_in_func(TreeNode):
def nested_in_class(): pass
def closure():
class Nested_in_closure: pass
ModuleBrowser(parent, file, _htest=True)
if __name__ == "__main__":
if len(sys.argv) == 1: # If pass file on command line, unittest fails.
from unittest import main
main('idlelib.idle_test.test_browser', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_module_browser)

205
.CondaPkg/env/Lib/idlelib/calltip.py vendored Normal file
View File

@@ -0,0 +1,205 @@
"""Pop up a reminder of how to call a function.
Call Tips are floating windows which display function, class, and method
parameter and docstring information when you type an opening parenthesis, and
which disappear when you type a closing parenthesis.
"""
import __main__
import inspect
import re
import sys
import textwrap
import types
from idlelib import calltip_w
from idlelib.hyperparser import HyperParser
class Calltip:
def __init__(self, editwin=None):
if editwin is None: # subprocess and test
self.editwin = None
else:
self.editwin = editwin
self.text = editwin.text
self.active_calltip = None
self._calltip_window = self._make_tk_calltip_window
def close(self):
self._calltip_window = None
def _make_tk_calltip_window(self):
# See __init__ for usage
return calltip_w.CalltipWindow(self.text)
def remove_calltip_window(self, event=None):
if self.active_calltip:
self.active_calltip.hidetip()
self.active_calltip = None
def force_open_calltip_event(self, event):
"The user selected the menu entry or hotkey, open the tip."
self.open_calltip(True)
return "break"
def try_open_calltip_event(self, event):
"""Happens when it would be nice to open a calltip, but not really
necessary, for example after an opening bracket, so function calls
won't be made.
"""
self.open_calltip(False)
def refresh_calltip_event(self, event):
if self.active_calltip and self.active_calltip.tipwindow:
self.open_calltip(False)
def open_calltip(self, evalfuncs):
"""Maybe close an existing calltip and maybe open a new calltip.
Called from (force_open|try_open|refresh)_calltip_event functions.
"""
hp = HyperParser(self.editwin, "insert")
sur_paren = hp.get_surrounding_brackets('(')
# If not inside parentheses, no calltip.
if not sur_paren:
self.remove_calltip_window()
return
# If a calltip is shown for the current parentheses, do
# nothing.
if self.active_calltip:
opener_line, opener_col = map(int, sur_paren[0].split('.'))
if (
(opener_line, opener_col) ==
(self.active_calltip.parenline, self.active_calltip.parencol)
):
return
hp.set_index(sur_paren[0])
try:
expression = hp.get_expression()
except ValueError:
expression = None
if not expression:
# No expression before the opening parenthesis, e.g.
# because it's in a string or the opener for a tuple:
# Do nothing.
return
# At this point, the current index is after an opening
# parenthesis, in a section of code, preceded by a valid
# expression. If there is a calltip shown, it's not for the
# same index and should be closed.
self.remove_calltip_window()
# Simple, fast heuristic: If the preceding expression includes
# an opening parenthesis, it likely includes a function call.
if not evalfuncs and (expression.find('(') != -1):
return
argspec = self.fetch_tip(expression)
if not argspec:
return
self.active_calltip = self._calltip_window()
self.active_calltip.showtip(argspec, sur_paren[0], sur_paren[1])
def fetch_tip(self, expression):
"""Return the argument list and docstring of a function or class.
If there is a Python subprocess, get the calltip there. Otherwise,
either this fetch_tip() is running in the subprocess or it was
called in an IDLE running without the subprocess.
The subprocess environment is that of the most recently run script. If
two unrelated modules are being edited some calltips in the current
module may be inoperative if the module was not the last to run.
To find methods, fetch_tip must be fed a fully qualified name.
"""
try:
rpcclt = self.editwin.flist.pyshell.interp.rpcclt
except AttributeError:
rpcclt = None
if rpcclt:
return rpcclt.remotecall("exec", "get_the_calltip",
(expression,), {})
else:
return get_argspec(get_entity(expression))
def get_entity(expression):
"""Return the object corresponding to expression evaluated
in a namespace spanning sys.modules and __main.dict__.
"""
if expression:
namespace = {**sys.modules, **__main__.__dict__}
try:
return eval(expression, namespace) # Only protect user code.
except BaseException:
# An uncaught exception closes idle, and eval can raise any
# exception, especially if user classes are involved.
return None
# The following are used in get_argspec and some in tests
_MAX_COLS = 85
_MAX_LINES = 5 # enough for bytes
_INDENT = ' '*4 # for wrapped signatures
_first_param = re.compile(r'(?<=\()\w*\,?\s*')
_default_callable_argspec = "See source or doc"
_invalid_method = "invalid method signature"
def get_argspec(ob):
'''Return a string describing the signature of a callable object, or ''.
For Python-coded functions and methods, the first line is introspected.
Delete 'self' parameter for classes (.__init__) and bound methods.
The next lines are the first lines of the doc string up to the first
empty line or _MAX_LINES. For builtins, this typically includes
the arguments in addition to the return value.
'''
# Determine function object fob to inspect.
try:
ob_call = ob.__call__
except BaseException: # Buggy user object could raise anything.
return '' # No popup for non-callables.
# For Get_argspecTest.test_buggy_getattr_class, CallA() & CallB().
fob = ob_call if isinstance(ob_call, types.MethodType) else ob
# Initialize argspec and wrap it to get lines.
try:
argspec = str(inspect.signature(fob))
except Exception as err:
msg = str(err)
if msg.startswith(_invalid_method):
return _invalid_method
else:
argspec = ''
if isinstance(fob, type) and argspec == '()':
# If fob has no argument, use default callable argspec.
argspec = _default_callable_argspec
lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT)
if len(argspec) > _MAX_COLS else [argspec] if argspec else [])
# Augment lines from docstring, if any, and join to get argspec.
doc = inspect.getdoc(ob)
if doc:
for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]:
line = line.strip()
if not line:
break
if len(line) > _MAX_COLS:
line = line[: _MAX_COLS - 3] + '...'
lines.append(line)
argspec = '\n'.join(lines)
return argspec or _default_callable_argspec
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_calltip', verbosity=2)

201
.CondaPkg/env/Lib/idlelib/calltip_w.py vendored Normal file
View File

@@ -0,0 +1,201 @@
"""A call-tip window class for Tkinter/IDLE.
After tooltip.py, which uses ideas gleaned from PySol.
Used by calltip.py.
"""
from tkinter import Label, LEFT, SOLID, TclError
from idlelib.tooltip import TooltipBase
HIDE_EVENT = "<<calltipwindow-hide>>"
HIDE_SEQUENCES = ("<Key-Escape>", "<FocusOut>")
CHECKHIDE_EVENT = "<<calltipwindow-checkhide>>"
CHECKHIDE_SEQUENCES = ("<KeyRelease>", "<ButtonRelease>")
CHECKHIDE_TIME = 100 # milliseconds
MARK_RIGHT = "calltipwindowregion_right"
class CalltipWindow(TooltipBase):
"""A call-tip widget for tkinter text widgets."""
def __init__(self, text_widget):
"""Create a call-tip; shown by showtip().
text_widget: a Text widget with code for which call-tips are desired
"""
# Note: The Text widget will be accessible as self.anchor_widget
super().__init__(text_widget)
self.label = self.text = None
self.parenline = self.parencol = self.lastline = None
self.hideid = self.checkhideid = None
self.checkhide_after_id = None
def get_position(self):
"""Choose the position of the call-tip."""
curline = int(self.anchor_widget.index("insert").split('.')[0])
if curline == self.parenline:
anchor_index = (self.parenline, self.parencol)
else:
anchor_index = (curline, 0)
box = self.anchor_widget.bbox("%d.%d" % anchor_index)
if not box:
box = list(self.anchor_widget.bbox("insert"))
# align to left of window
box[0] = 0
box[2] = 0
return box[0] + 2, box[1] + box[3]
def position_window(self):
"Reposition the window if needed."
curline = int(self.anchor_widget.index("insert").split('.')[0])
if curline == self.lastline:
return
self.lastline = curline
self.anchor_widget.see("insert")
super().position_window()
def showtip(self, text, parenleft, parenright):
"""Show the call-tip, bind events which will close it and reposition it.
text: the text to display in the call-tip
parenleft: index of the opening parenthesis in the text widget
parenright: index of the closing parenthesis in the text widget,
or the end of the line if there is no closing parenthesis
"""
# Only called in calltip.Calltip, where lines are truncated
self.text = text
if self.tipwindow or not self.text:
return
self.anchor_widget.mark_set(MARK_RIGHT, parenright)
self.parenline, self.parencol = map(
int, self.anchor_widget.index(parenleft).split("."))
super().showtip()
self._bind_events()
def showcontents(self):
"""Create the call-tip widget."""
self.label = Label(self.tipwindow, text=self.text, justify=LEFT,
background="#ffffd0", foreground="black",
relief=SOLID, borderwidth=1,
font=self.anchor_widget['font'])
self.label.pack()
def checkhide_event(self, event=None):
"""Handle CHECK_HIDE_EVENT: call hidetip or reschedule."""
if not self.tipwindow:
# If the event was triggered by the same event that unbound
# this function, the function will be called nevertheless,
# so do nothing in this case.
return None
# Hide the call-tip if the insertion cursor moves outside of the
# parenthesis.
curline, curcol = map(int, self.anchor_widget.index("insert").split('.'))
if curline < self.parenline or \
(curline == self.parenline and curcol <= self.parencol) or \
self.anchor_widget.compare("insert", ">", MARK_RIGHT):
self.hidetip()
return "break"
# Not hiding the call-tip.
self.position_window()
# Re-schedule this function to be called again in a short while.
if self.checkhide_after_id is not None:
self.anchor_widget.after_cancel(self.checkhide_after_id)
self.checkhide_after_id = \
self.anchor_widget.after(CHECKHIDE_TIME, self.checkhide_event)
return None
def hide_event(self, event):
"""Handle HIDE_EVENT by calling hidetip."""
if not self.tipwindow:
# See the explanation in checkhide_event.
return None
self.hidetip()
return "break"
def hidetip(self):
"""Hide the call-tip."""
if not self.tipwindow:
return
try:
self.label.destroy()
except TclError:
pass
self.label = None
self.parenline = self.parencol = self.lastline = None
try:
self.anchor_widget.mark_unset(MARK_RIGHT)
except TclError:
pass
try:
self._unbind_events()
except (TclError, ValueError):
# ValueError may be raised by MultiCall
pass
super().hidetip()
def _bind_events(self):
"""Bind event handlers."""
self.checkhideid = self.anchor_widget.bind(CHECKHIDE_EVENT,
self.checkhide_event)
for seq in CHECKHIDE_SEQUENCES:
self.anchor_widget.event_add(CHECKHIDE_EVENT, seq)
self.anchor_widget.after(CHECKHIDE_TIME, self.checkhide_event)
self.hideid = self.anchor_widget.bind(HIDE_EVENT,
self.hide_event)
for seq in HIDE_SEQUENCES:
self.anchor_widget.event_add(HIDE_EVENT, seq)
def _unbind_events(self):
"""Unbind event handlers."""
for seq in CHECKHIDE_SEQUENCES:
self.anchor_widget.event_delete(CHECKHIDE_EVENT, seq)
self.anchor_widget.unbind(CHECKHIDE_EVENT, self.checkhideid)
self.checkhideid = None
for seq in HIDE_SEQUENCES:
self.anchor_widget.event_delete(HIDE_EVENT, seq)
self.anchor_widget.unbind(HIDE_EVENT, self.hideid)
self.hideid = None
def _calltip_window(parent): # htest #
from tkinter import Toplevel, Text, LEFT, BOTH
top = Toplevel(parent)
top.title("Test call-tips")
x, y = map(int, parent.geometry().split('+')[1:])
top.geometry("250x100+%d+%d" % (x + 175, y + 150))
text = Text(top)
text.pack(side=LEFT, fill=BOTH, expand=1)
text.insert("insert", "string.split")
top.update()
calltip = CalltipWindow(text)
def calltip_show(event):
calltip.showtip("(s='Hello world')", "insert", "end")
def calltip_hide(event):
calltip.hidetip()
text.event_add("<<calltip-show>>", "(")
text.event_add("<<calltip-hide>>", ")")
text.bind("<<calltip-show>>", calltip_show)
text.bind("<<calltip-hide>>", calltip_hide)
text.focus_set()
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_calltip_w', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_calltip_window)

270
.CondaPkg/env/Lib/idlelib/codecontext.py vendored Normal file
View File

@@ -0,0 +1,270 @@
"""codecontext - display the block context above the edit window
Once code has scrolled off the top of a window, it can be difficult to
determine which block you are in. This extension implements a pane at the top
of each IDLE edit window which provides block structure hints. These hints are
the lines which contain the block opening keywords, e.g. 'if', for the
enclosing block. The number of hint lines is determined by the maxlines
variable in the codecontext section of config-extensions.def. Lines which do
not open blocks are not shown in the context hints pane.
For EditorWindows, <<toggle-code-context>> is bound to CodeContext(self).
toggle_code_context_event.
"""
import re
from sys import maxsize as INFINITY
from tkinter import Frame, Text, TclError
from tkinter.constants import NSEW, SUNKEN
from idlelib.config import idleConf
BLOCKOPENERS = {'class', 'def', 'if', 'elif', 'else', 'while', 'for',
'try', 'except', 'finally', 'with', 'async'}
def get_spaces_firstword(codeline, c=re.compile(r"^(\s*)(\w*)")):
"Extract the beginning whitespace and first word from codeline."
return c.match(codeline).groups()
def get_line_info(codeline):
"""Return tuple of (line indent value, codeline, block start keyword).
The indentation of empty lines (or comment lines) is INFINITY.
If the line does not start a block, the keyword value is False.
"""
spaces, firstword = get_spaces_firstword(codeline)
indent = len(spaces)
if len(codeline) == indent or codeline[indent] == '#':
indent = INFINITY
opener = firstword in BLOCKOPENERS and firstword
return indent, codeline, opener
class CodeContext:
"Display block context above the edit window."
UPDATEINTERVAL = 100 # millisec
def __init__(self, editwin):
"""Initialize settings for context block.
editwin is the Editor window for the context block.
self.text is the editor window text widget.
self.context displays the code context text above the editor text.
Initially None, it is toggled via <<toggle-code-context>>.
self.topvisible is the number of the top text line displayed.
self.info is a list of (line number, indent level, line text,
block keyword) tuples for the block structure above topvisible.
self.info[0] is initialized with a 'dummy' line which
starts the toplevel 'block' of the module.
self.t1 and self.t2 are two timer events on the editor text widget to
monitor for changes to the context text or editor font.
"""
self.editwin = editwin
self.text = editwin.text
self._reset()
def _reset(self):
self.context = None
self.cell00 = None
self.t1 = None
self.topvisible = 1
self.info = [(0, -1, "", False)]
@classmethod
def reload(cls):
"Load class variables from config."
cls.context_depth = idleConf.GetOption("extensions", "CodeContext",
"maxlines", type="int",
default=15)
def __del__(self):
"Cancel scheduled events."
if self.t1 is not None:
try:
self.text.after_cancel(self.t1)
except TclError: # pragma: no cover
pass
self.t1 = None
def toggle_code_context_event(self, event=None):
"""Toggle code context display.
If self.context doesn't exist, create it to match the size of the editor
window text (toggle on). If it does exist, destroy it (toggle off).
Return 'break' to complete the processing of the binding.
"""
if self.context is None:
# Calculate the border width and horizontal padding required to
# align the context with the text in the main Text widget.
#
# All values are passed through getint(), since some
# values may be pixel objects, which can't simply be added to ints.
widgets = self.editwin.text, self.editwin.text_frame
# Calculate the required horizontal padding and border width.
padx = 0
border = 0
for widget in widgets:
info = (widget.grid_info()
if widget is self.editwin.text
else widget.pack_info())
padx += widget.tk.getint(info['padx'])
padx += widget.tk.getint(widget.cget('padx'))
border += widget.tk.getint(widget.cget('border'))
context = self.context = Text(
self.editwin.text_frame,
height=1,
width=1, # Don't request more than we get.
highlightthickness=0,
padx=padx, border=border, relief=SUNKEN, state='disabled')
self.update_font()
self.update_highlight_colors()
context.bind('<ButtonRelease-1>', self.jumptoline)
# Get the current context and initiate the recurring update event.
self.timer_event()
# Grid the context widget above the text widget.
context.grid(row=0, column=1, sticky=NSEW)
line_number_colors = idleConf.GetHighlight(idleConf.CurrentTheme(),
'linenumber')
self.cell00 = Frame(self.editwin.text_frame,
bg=line_number_colors['background'])
self.cell00.grid(row=0, column=0, sticky=NSEW)
menu_status = 'Hide'
else:
self.context.destroy()
self.context = None
self.cell00.destroy()
self.cell00 = None
self.text.after_cancel(self.t1)
self._reset()
menu_status = 'Show'
self.editwin.update_menu_label(menu='options', index='*ode*ontext',
label=f'{menu_status} Code Context')
return "break"
def get_context(self, new_topvisible, stopline=1, stopindent=0):
"""Return a list of block line tuples and the 'last' indent.
The tuple fields are (linenum, indent, text, opener).
The list represents header lines from new_topvisible back to
stopline with successively shorter indents > stopindent.
The list is returned ordered by line number.
Last indent returned is the smallest indent observed.
"""
assert stopline > 0
lines = []
# The indentation level we are currently in.
lastindent = INFINITY
# For a line to be interesting, it must begin with a block opening
# keyword, and have less indentation than lastindent.
for linenum in range(new_topvisible, stopline-1, -1):
codeline = self.text.get(f'{linenum}.0', f'{linenum}.end')
indent, text, opener = get_line_info(codeline)
if indent < lastindent:
lastindent = indent
if opener in ("else", "elif"):
# Also show the if statement.
lastindent += 1
if opener and linenum < new_topvisible and indent >= stopindent:
lines.append((linenum, indent, text, opener))
if lastindent <= stopindent:
break
lines.reverse()
return lines, lastindent
def update_code_context(self):
"""Update context information and lines visible in the context pane.
No update is done if the text hasn't been scrolled. If the text
was scrolled, the lines that should be shown in the context will
be retrieved and the context area will be updated with the code,
up to the number of maxlines.
"""
new_topvisible = self.editwin.getlineno("@0,0")
if self.topvisible == new_topvisible: # Haven't scrolled.
return
if self.topvisible < new_topvisible: # Scroll down.
lines, lastindent = self.get_context(new_topvisible,
self.topvisible)
# Retain only context info applicable to the region
# between topvisible and new_topvisible.
while self.info[-1][1] >= lastindent:
del self.info[-1]
else: # self.topvisible > new_topvisible: # Scroll up.
stopindent = self.info[-1][1] + 1
# Retain only context info associated
# with lines above new_topvisible.
while self.info[-1][0] >= new_topvisible:
stopindent = self.info[-1][1]
del self.info[-1]
lines, lastindent = self.get_context(new_topvisible,
self.info[-1][0]+1,
stopindent)
self.info.extend(lines)
self.topvisible = new_topvisible
# Last context_depth context lines.
context_strings = [x[2] for x in self.info[-self.context_depth:]]
showfirst = 0 if context_strings[0] else 1
# Update widget.
self.context['height'] = len(context_strings) - showfirst
self.context['state'] = 'normal'
self.context.delete('1.0', 'end')
self.context.insert('end', '\n'.join(context_strings[showfirst:]))
self.context['state'] = 'disabled'
def jumptoline(self, event=None):
""" Show clicked context line at top of editor.
If a selection was made, don't jump; allow copying.
If no visible context, show the top line of the file.
"""
try:
self.context.index("sel.first")
except TclError:
lines = len(self.info)
if lines == 1: # No context lines are showing.
newtop = 1
else:
# Line number clicked.
contextline = int(float(self.context.index('insert')))
# Lines not displayed due to maxlines.
offset = max(1, lines - self.context_depth) - 1
newtop = self.info[offset + contextline][0]
self.text.yview(f'{newtop}.0')
self.update_code_context()
def timer_event(self):
"Event on editor text widget triggered every UPDATEINTERVAL ms."
if self.context is not None:
self.update_code_context()
self.t1 = self.text.after(self.UPDATEINTERVAL, self.timer_event)
def update_font(self):
if self.context is not None:
font = idleConf.GetFont(self.text, 'main', 'EditorWindow')
self.context['font'] = font
def update_highlight_colors(self):
if self.context is not None:
colors = idleConf.GetHighlight(idleConf.CurrentTheme(), 'context')
self.context['background'] = colors['background']
self.context['foreground'] = colors['foreground']
if self.cell00 is not None:
line_number_colors = idleConf.GetHighlight(idleConf.CurrentTheme(),
'linenumber')
self.cell00.config(bg=line_number_colors['background'])
CodeContext.reload()
if __name__ == "__main__":
from unittest import main
main('idlelib.idle_test.test_codecontext', verbosity=2, exit=False)
# Add htest.

384
.CondaPkg/env/Lib/idlelib/colorizer.py vendored Normal file
View File

@@ -0,0 +1,384 @@
import builtins
import keyword
import re
import time
from idlelib.config import idleConf
from idlelib.delegator import Delegator
DEBUG = False
def any(name, alternates):
"Return a named group pattern matching list of alternates."
return "(?P<%s>" % name + "|".join(alternates) + ")"
def make_pat():
kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b"
match_softkw = (
r"^[ \t]*" + # at beginning of line + possible indentation
r"(?P<MATCH_SOFTKW>match)\b" +
r"(?![ \t]*(?:" + "|".join([ # not followed by ...
r"[:,;=^&|@~)\]}]", # a character which means it can't be a
# pattern-matching statement
r"\b(?:" + r"|".join(keyword.kwlist) + r")\b", # a keyword
]) +
r"))"
)
case_default = (
r"^[ \t]*" + # at beginning of line + possible indentation
r"(?P<CASE_SOFTKW>case)" +
r"[ \t]+(?P<CASE_DEFAULT_UNDERSCORE>_\b)"
)
case_softkw_and_pattern = (
r"^[ \t]*" + # at beginning of line + possible indentation
r"(?P<CASE_SOFTKW2>case)\b" +
r"(?![ \t]*(?:" + "|".join([ # not followed by ...
r"_\b", # a lone underscore
r"[:,;=^&|@~)\]}]", # a character which means it can't be a
# pattern-matching case
r"\b(?:" + r"|".join(keyword.kwlist) + r")\b", # a keyword
]) +
r"))"
)
builtinlist = [str(name) for name in dir(builtins)
if not name.startswith('_') and
name not in keyword.kwlist]
builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b"
comment = any("COMMENT", [r"#[^\n]*"])
stringprefix = r"(?i:r|u|f|fr|rf|b|br|rb)?"
sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?"
dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?'
sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
dq3string = stringprefix + r'"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
string = any("STRING", [sq3string, dq3string, sqstring, dqstring])
prog = re.compile("|".join([
builtin, comment, string, kw,
match_softkw, case_default,
case_softkw_and_pattern,
any("SYNC", [r"\n"]),
]),
re.DOTALL | re.MULTILINE)
return prog
prog = make_pat()
idprog = re.compile(r"\s+(\w+)")
prog_group_name_to_tag = {
"MATCH_SOFTKW": "KEYWORD",
"CASE_SOFTKW": "KEYWORD",
"CASE_DEFAULT_UNDERSCORE": "KEYWORD",
"CASE_SOFTKW2": "KEYWORD",
}
def matched_named_groups(re_match):
"Get only the non-empty named groups from an re.Match object."
return ((k, v) for (k, v) in re_match.groupdict().items() if v)
def color_config(text):
"""Set color options of Text widget.
If ColorDelegator is used, this should be called first.
"""
# Called from htest, TextFrame, Editor, and Turtledemo.
# Not automatic because ColorDelegator does not know 'text'.
theme = idleConf.CurrentTheme()
normal_colors = idleConf.GetHighlight(theme, 'normal')
cursor_color = idleConf.GetHighlight(theme, 'cursor')['foreground']
select_colors = idleConf.GetHighlight(theme, 'hilite')
text.config(
foreground=normal_colors['foreground'],
background=normal_colors['background'],
insertbackground=cursor_color,
selectforeground=select_colors['foreground'],
selectbackground=select_colors['background'],
inactiveselectbackground=select_colors['background'], # new in 8.5
)
class ColorDelegator(Delegator):
"""Delegator for syntax highlighting (text coloring).
Instance variables:
delegate: Delegator below this one in the stack, meaning the
one this one delegates to.
Used to track state:
after_id: Identifier for scheduled after event, which is a
timer for colorizing the text.
allow_colorizing: Boolean toggle for applying colorizing.
colorizing: Boolean flag when colorizing is in process.
stop_colorizing: Boolean flag to end an active colorizing
process.
"""
def __init__(self):
Delegator.__init__(self)
self.init_state()
self.prog = prog
self.idprog = idprog
self.LoadTagDefs()
def init_state(self):
"Initialize variables that track colorizing state."
self.after_id = None
self.allow_colorizing = True
self.stop_colorizing = False
self.colorizing = False
def setdelegate(self, delegate):
"""Set the delegate for this instance.
A delegate is an instance of a Delegator class and each
delegate points to the next delegator in the stack. This
allows multiple delegators to be chained together for a
widget. The bottom delegate for a colorizer is a Text
widget.
If there is a delegate, also start the colorizing process.
"""
if self.delegate is not None:
self.unbind("<<toggle-auto-coloring>>")
Delegator.setdelegate(self, delegate)
if delegate is not None:
self.config_colors()
self.bind("<<toggle-auto-coloring>>", self.toggle_colorize_event)
self.notify_range("1.0", "end")
else:
# No delegate - stop any colorizing.
self.stop_colorizing = True
self.allow_colorizing = False
def config_colors(self):
"Configure text widget tags with colors from tagdefs."
for tag, cnf in self.tagdefs.items():
self.tag_configure(tag, **cnf)
self.tag_raise('sel')
def LoadTagDefs(self):
"Create dictionary of tag names to text colors."
theme = idleConf.CurrentTheme()
self.tagdefs = {
"COMMENT": idleConf.GetHighlight(theme, "comment"),
"KEYWORD": idleConf.GetHighlight(theme, "keyword"),
"BUILTIN": idleConf.GetHighlight(theme, "builtin"),
"STRING": idleConf.GetHighlight(theme, "string"),
"DEFINITION": idleConf.GetHighlight(theme, "definition"),
"SYNC": {'background': None, 'foreground': None},
"TODO": {'background': None, 'foreground': None},
"ERROR": idleConf.GetHighlight(theme, "error"),
# "hit" is used by ReplaceDialog to mark matches. It shouldn't be changed by Colorizer, but
# that currently isn't technically possible. This should be moved elsewhere in the future
# when fixing the "hit" tag's visibility, or when the replace dialog is replaced with a
# non-modal alternative.
"hit": idleConf.GetHighlight(theme, "hit"),
}
if DEBUG: print('tagdefs', self.tagdefs)
def insert(self, index, chars, tags=None):
"Insert chars into widget at index and mark for colorizing."
index = self.index(index)
self.delegate.insert(index, chars, tags)
self.notify_range(index, index + "+%dc" % len(chars))
def delete(self, index1, index2=None):
"Delete chars between indexes and mark for colorizing."
index1 = self.index(index1)
self.delegate.delete(index1, index2)
self.notify_range(index1)
def notify_range(self, index1, index2=None):
"Mark text changes for processing and restart colorizing, if active."
self.tag_add("TODO", index1, index2)
if self.after_id:
if DEBUG: print("colorizing already scheduled")
return
if self.colorizing:
self.stop_colorizing = True
if DEBUG: print("stop colorizing")
if self.allow_colorizing:
if DEBUG: print("schedule colorizing")
self.after_id = self.after(1, self.recolorize)
return
def close(self):
if self.after_id:
after_id = self.after_id
self.after_id = None
if DEBUG: print("cancel scheduled recolorizer")
self.after_cancel(after_id)
self.allow_colorizing = False
self.stop_colorizing = True
def toggle_colorize_event(self, event=None):
"""Toggle colorizing on and off.
When toggling off, if colorizing is scheduled or is in
process, it will be cancelled and/or stopped.
When toggling on, colorizing will be scheduled.
"""
if self.after_id:
after_id = self.after_id
self.after_id = None
if DEBUG: print("cancel scheduled recolorizer")
self.after_cancel(after_id)
if self.allow_colorizing and self.colorizing:
if DEBUG: print("stop colorizing")
self.stop_colorizing = True
self.allow_colorizing = not self.allow_colorizing
if self.allow_colorizing and not self.colorizing:
self.after_id = self.after(1, self.recolorize)
if DEBUG:
print("auto colorizing turned",
"on" if self.allow_colorizing else "off")
return "break"
def recolorize(self):
"""Timer event (every 1ms) to colorize text.
Colorizing is only attempted when the text widget exists,
when colorizing is toggled on, and when the colorizing
process is not already running.
After colorizing is complete, some cleanup is done to
make sure that all the text has been colorized.
"""
self.after_id = None
if not self.delegate:
if DEBUG: print("no delegate")
return
if not self.allow_colorizing:
if DEBUG: print("auto colorizing is off")
return
if self.colorizing:
if DEBUG: print("already colorizing")
return
try:
self.stop_colorizing = False
self.colorizing = True
if DEBUG: print("colorizing...")
t0 = time.perf_counter()
self.recolorize_main()
t1 = time.perf_counter()
if DEBUG: print("%.3f seconds" % (t1-t0))
finally:
self.colorizing = False
if self.allow_colorizing and self.tag_nextrange("TODO", "1.0"):
if DEBUG: print("reschedule colorizing")
self.after_id = self.after(1, self.recolorize)
def recolorize_main(self):
"Evaluate text and apply colorizing tags."
next = "1.0"
while todo_tag_range := self.tag_nextrange("TODO", next):
self.tag_remove("SYNC", todo_tag_range[0], todo_tag_range[1])
sync_tag_range = self.tag_prevrange("SYNC", todo_tag_range[0])
head = sync_tag_range[1] if sync_tag_range else "1.0"
chars = ""
next = head
lines_to_get = 1
ok = False
while not ok:
mark = next
next = self.index(mark + "+%d lines linestart" %
lines_to_get)
lines_to_get = min(lines_to_get * 2, 100)
ok = "SYNC" in self.tag_names(next + "-1c")
line = self.get(mark, next)
##print head, "get", mark, next, "->", repr(line)
if not line:
return
for tag in self.tagdefs:
self.tag_remove(tag, mark, next)
chars += line
self._add_tags_in_section(chars, head)
if "SYNC" in self.tag_names(next + "-1c"):
head = next
chars = ""
else:
ok = False
if not ok:
# We're in an inconsistent state, and the call to
# update may tell us to stop. It may also change
# the correct value for "next" (since this is a
# line.col string, not a true mark). So leave a
# crumb telling the next invocation to resume here
# in case update tells us to leave.
self.tag_add("TODO", next)
self.update_idletasks()
if self.stop_colorizing:
if DEBUG: print("colorizing stopped")
return
def _add_tag(self, start, end, head, matched_group_name):
"""Add a tag to a given range in the text widget.
This is a utility function, receiving the range as `start` and
`end` positions, each of which is a number of characters
relative to the given `head` index in the text widget.
The tag to add is determined by `matched_group_name`, which is
the name of a regular expression "named group" as matched by
by the relevant highlighting regexps.
"""
tag = prog_group_name_to_tag.get(matched_group_name,
matched_group_name)
self.tag_add(tag,
f"{head}+{start:d}c",
f"{head}+{end:d}c")
def _add_tags_in_section(self, chars, head):
"""Parse and add highlighting tags to a given part of the text.
`chars` is a string with the text to parse and to which
highlighting is to be applied.
`head` is the index in the text widget where the text is found.
"""
for m in self.prog.finditer(chars):
for name, matched_text in matched_named_groups(m):
a, b = m.span(name)
self._add_tag(a, b, head, name)
if matched_text in ("def", "class"):
if m1 := self.idprog.match(chars, b):
a, b = m1.span(1)
self._add_tag(a, b, head, "DEFINITION")
def removecolors(self):
"Remove all colorizing tags."
for tag in self.tagdefs:
self.tag_remove(tag, "1.0", "end")
def _color_delegator(parent): # htest #
from tkinter import Toplevel, Text
from idlelib.idle_test.test_colorizer import source
from idlelib.percolator import Percolator
top = Toplevel(parent)
top.title("Test ColorDelegator")
x, y = map(int, parent.geometry().split('+')[1:])
top.geometry("700x550+%d+%d" % (x + 20, y + 175))
text = Text(top, background="white")
text.pack(expand=1, fill="both")
text.insert("insert", source)
text.focus_set()
color_config(text)
p = Percolator(text)
d = ColorDelegator()
p.insertfilter(d)
if __name__ == "__main__":
from unittest import main
main('idlelib.idle_test.test_colorizer', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_color_delegator)

View File

@@ -0,0 +1,62 @@
# config-extensions.def
#
# The following sections are for features that are no longer extensions.
# Their options values are left here for back-compatibility.
[AutoComplete]
popupwait= 2000
[CodeContext]
maxlines= 15
[FormatParagraph]
max-width= 72
[ParenMatch]
style= expression
flash-delay= 500
bell= True
# IDLE reads several config files to determine user preferences. This
# file is the default configuration file for IDLE extensions settings.
#
# Each extension must have at least one section, named after the
# extension module. This section must contain an 'enable' item (=True to
# enable the extension, =False to disable it), it may contain
# 'enable_editor' or 'enable_shell' items, to apply it only to editor ir
# shell windows, and may also contain any other general configuration
# items for the extension. Other True/False values will also be
# recognized as boolean by the Extension Configuration dialog.
#
# Each extension must define at least one section named
# ExtensionName_bindings or ExtensionName_cfgBindings. If present,
# ExtensionName_bindings defines virtual event bindings for the
# extension that are not user re-configurable. If present,
# ExtensionName_cfgBindings defines virtual event bindings for the
# extension that may be sensibly re-configured.
#
# If there are no keybindings for a menus' virtual events, include lines
# like <<toggle-code-context>>=.
#
# Currently it is necessary to manually modify this file to change
# extension key bindings and default values. To customize, create
# ~/.idlerc/config-extensions.cfg and append the appropriate customized
# section(s). Those sections will override the defaults in this file.
#
# Note: If a keybinding is already in use when the extension is loaded,
# the extension's virtual event's keybinding will be set to ''.
#
# See config-keys.def for notes on specifying keys and extend.txt for
# information on creating IDLE extensions.
# A fake extension for testing and example purposes. When enabled and
# invoked, inserts or deletes z-text at beginning of every line.
[ZzDummy]
enable= False
enable_shell = False
enable_editor = True
z-text= Z
[ZzDummy_cfgBindings]
z-in= <Control-Shift-KeyRelease-Insert>
[ZzDummy_bindings]
z-out= <Control-Shift-KeyRelease-Delete>

View File

@@ -0,0 +1,105 @@
# IDLE reads several config files to determine user preferences. This
# file is the default config file for idle highlight theme settings.
[IDLE Classic]
normal-foreground= #000000
normal-background= #ffffff
keyword-foreground= #ff7700
keyword-background= #ffffff
builtin-foreground= #900090
builtin-background= #ffffff
comment-foreground= #dd0000
comment-background= #ffffff
string-foreground= #00aa00
string-background= #ffffff
definition-foreground= #0000ff
definition-background= #ffffff
hilite-foreground= #000000
hilite-background= gray
break-foreground= black
break-background= #ffff55
hit-foreground= #ffffff
hit-background= #000000
error-foreground= #000000
error-background= #ff7777
context-foreground= #000000
context-background= lightgray
linenumber-foreground= gray
linenumber-background= #ffffff
#cursor (only foreground can be set, restart IDLE)
cursor-foreground= black
#shell window
stdout-foreground= blue
stdout-background= #ffffff
stderr-foreground= red
stderr-background= #ffffff
console-foreground= #770000
console-background= #ffffff
[IDLE New]
normal-foreground= #000000
normal-background= #ffffff
keyword-foreground= #ff7700
keyword-background= #ffffff
builtin-foreground= #900090
builtin-background= #ffffff
comment-foreground= #dd0000
comment-background= #ffffff
string-foreground= #00aa00
string-background= #ffffff
definition-foreground= #0000ff
definition-background= #ffffff
hilite-foreground= #000000
hilite-background= gray
break-foreground= black
break-background= #ffff55
hit-foreground= #ffffff
hit-background= #000000
error-foreground= #000000
error-background= #ff7777
context-foreground= #000000
context-background= lightgray
linenumber-foreground= gray
linenumber-background= #ffffff
#cursor (only foreground can be set, restart IDLE)
cursor-foreground= black
#shell window
stdout-foreground= blue
stdout-background= #ffffff
stderr-foreground= red
stderr-background= #ffffff
console-foreground= #770000
console-background= #ffffff
[IDLE Dark]
comment-foreground = #dd0000
console-foreground = #ff4d4d
error-foreground = #FFFFFF
hilite-background = #7e7e7e
string-foreground = #02ff02
stderr-background = #002240
stderr-foreground = #ffb3b3
console-background = #002240
hit-background = #fbfbfb
string-background = #002240
normal-background = #002240
hilite-foreground = #FFFFFF
keyword-foreground = #ff8000
error-background = #c86464
keyword-background = #002240
builtin-background = #002240
break-background = #808000
builtin-foreground = #ff00ff
definition-foreground = #5e5eff
stdout-foreground = #c2d1fa
definition-background = #002240
normal-foreground = #FFFFFF
cursor-foreground = #ffffff
stdout-background = #002240
hit-foreground = #002240
comment-background = #002240
break-foreground = #FFFFFF
context-foreground= #ffffff
context-background= #454545
linenumber-foreground= gray
linenumber-background= #002240

View File

@@ -0,0 +1,309 @@
# IDLE reads several config files to determine user preferences. This
# file is the default config file for idle key binding settings.
# Where multiple keys are specified for an action: if they are separated
# by a space (eg. action=<key1> <key2>) then the keys are alternatives, if
# there is no space (eg. action=<key1><key2>) then the keys comprise a
# single 'emacs style' multi-keystoke binding. The tk event specifier 'Key'
# is used in all cases, for consistency in auto key conflict checking in the
# configuration gui.
[IDLE Classic Windows]
copy=<Control-Key-c> <Control-Key-C>
cut=<Control-Key-x> <Control-Key-X>
paste=<Control-Key-v> <Control-Key-V>
beginning-of-line= <Key-Home>
center-insert=<Control-Key-l> <Control-Key-L>
close-all-windows=<Control-Key-q> <Control-Key-Q>
close-window=<Alt-Key-F4> <Meta-Key-F4>
do-nothing=<Control-Key-F12>
end-of-file=<Control-Key-d> <Control-Key-D>
python-docs=<Key-F1>
python-context-help=<Shift-Key-F1>
history-next=<Alt-Key-n> <Meta-Key-n> <Alt-Key-N> <Meta-Key-N>
history-previous=<Alt-Key-p> <Meta-Key-p> <Alt-Key-P> <Meta-Key-P>
interrupt-execution=<Control-Key-c> <Control-Key-C>
view-restart=<Key-F6>
restart-shell=<Control-Key-F6>
open-class-browser=<Alt-Key-c> <Meta-Key-c> <Alt-Key-C> <Meta-Key-C>
open-module=<Alt-Key-m> <Meta-Key-m> <Alt-Key-M> <Meta-Key-M>
open-new-window=<Control-Key-n> <Control-Key-N>
open-window-from-file=<Control-Key-o> <Control-Key-O>
plain-newline-and-indent=<Control-Key-j> <Control-Key-J>
print-window=<Control-Key-p> <Control-Key-P>
redo=<Control-Shift-Key-Z> <Control-Shift-Key-z>
remove-selection=<Key-Escape>
save-copy-of-window-as-file=<Alt-Shift-Key-S> <Alt-Shift-Key-s>
save-window-as-file=<Control-Shift-Key-S> <Control-Shift-Key-s>
save-window=<Control-Key-s> <Control-Key-S>
select-all=<Control-Key-a> <Control-Key-A>
toggle-auto-coloring=<Control-Key-slash>
undo=<Control-Key-z> <Control-Key-Z>
find=<Control-Key-f> <Control-Key-F>
find-again=<Control-Key-g> <Key-F3> <Control-Key-G>
find-in-files=<Alt-Key-F3> <Meta-Key-F3>
find-selection=<Control-Key-F3>
replace=<Control-Key-h> <Control-Key-H>
goto-line=<Alt-Key-g> <Meta-Key-g> <Alt-Key-G> <Meta-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=<Alt-Key-3> <Meta-Key-3>
uncomment-region=<Alt-Key-4> <Meta-Key-4>
tabify-region=<Alt-Key-5> <Meta-Key-5>
untabify-region=<Alt-Key-6> <Meta-Key-6>
toggle-tabs=<Alt-Key-t> <Meta-Key-t> <Alt-Key-T> <Meta-Key-T>
change-indentwidth=<Alt-Key-u> <Meta-Key-u> <Alt-Key-U> <Meta-Key-U>
del-word-left=<Control-Key-BackSpace>
del-word-right=<Control-Key-Delete>
force-open-completions= <Control-Key-space>
expand-word= <Alt-Key-slash>
force-open-calltip= <Control-Key-backslash>
format-paragraph= <Alt-Key-q>
flash-paren= <Control-Key-0>
run-module= <Key-F5>
run-custom= <Shift-Key-F5>
check-module= <Alt-Key-x>
zoom-height= <Alt-Key-2>
[IDLE Classic Unix]
copy=<Alt-Key-w> <Meta-Key-w>
cut=<Control-Key-w>
paste=<Control-Key-y>
beginning-of-line=<Control-Key-a> <Key-Home>
center-insert=<Control-Key-l>
close-all-windows=<Control-Key-x><Control-Key-c>
close-window=<Control-Key-x><Control-Key-0>
do-nothing=<Control-Key-x>
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-x><Control-Key-b>
open-module=<Control-Key-x><Control-Key-m>
open-new-window=<Control-Key-x><Control-Key-n>
open-window-from-file=<Control-Key-x><Control-Key-f>
plain-newline-and-indent=<Control-Key-j>
print-window=<Control-x><Control-Key-p>
python-docs=<Control-Key-h>
python-context-help=<Control-Shift-Key-H>
redo=<Alt-Key-z> <Meta-Key-z>
remove-selection=<Key-Escape>
save-copy-of-window-as-file=<Control-Key-x><Control-Key-y>
save-window-as-file=<Control-Key-x><Control-Key-w>
save-window=<Control-Key-x><Control-Key-s>
select-all=<Alt-Key-a> <Meta-Key-a>
toggle-auto-coloring=<Control-Key-slash>
undo=<Control-Key-z>
find=<Control-Key-u><Control-Key-u><Control-Key-s>
find-again=<Control-Key-u><Control-Key-s>
find-in-files=<Alt-Key-s> <Meta-Key-s>
find-selection=<Control-Key-s>
replace=<Control-Key-r>
goto-line=<Alt-Key-g> <Meta-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=<Alt-Key-3>
uncomment-region=<Alt-Key-4>
tabify-region=<Alt-Key-5>
untabify-region=<Alt-Key-6>
toggle-tabs=<Alt-Key-t>
change-indentwidth=<Alt-Key-u>
del-word-left=<Alt-Key-BackSpace>
del-word-right=<Alt-Key-d>
force-open-completions= <Control-Key-space>
expand-word= <Alt-Key-slash>
force-open-calltip= <Control-Key-backslash>
format-paragraph= <Alt-Key-q>
flash-paren= <Control-Key-0>
run-module= <Key-F5>
run-custom= <Shift-Key-F5>
check-module= <Alt-Key-x>
zoom-height= <Alt-Key-2>
[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>
force-open-completions= <Control-Key-space>
expand-word= <Alt-Key-slash>
force-open-calltip= <Control-Key-backslash>
format-paragraph= <Alt-Key-q>
flash-paren= <Control-Key-0>
run-module= <Key-F5>
run-custom= <Shift-Key-F5>
check-module= <Alt-Key-x>
zoom-height= <Alt-Key-2>
[IDLE Classic Mac]
copy=<Command-Key-c>
cut=<Command-Key-x>
paste=<Command-Key-v>
beginning-of-line= <Key-Home>
center-insert=<Control-Key-l>
close-all-windows=<Command-Key-q>
close-window=<Command-Key-w>
do-nothing=<Control-Key-F12>
end-of-file=<Control-Key-d>
python-docs=<Key-F1>
python-context-help=<Shift-Key-F1>
history-next=<Control-Key-n>
history-previous=<Control-Key-p>
interrupt-execution=<Control-Key-c>
view-restart=<Key-F6>
restart-shell=<Control-Key-F6>
open-class-browser=<Command-Key-b>
open-module=<Command-Key-m>
open-new-window=<Command-Key-n>
open-window-from-file=<Command-Key-o>
plain-newline-and-indent=<Control-Key-j>
print-window=<Command-Key-p>
redo=<Shift-Command-Key-Z>
remove-selection=<Key-Escape>
save-window-as-file=<Shift-Command-Key-S>
save-window=<Command-Key-s>
save-copy-of-window-as-file=<Option-Command-Key-s>
select-all=<Command-Key-a>
toggle-auto-coloring=<Control-Key-slash>
undo=<Command-Key-z>
find=<Command-Key-f>
find-again=<Command-Key-g> <Key-F3>
find-in-files=<Command-Key-F3>
find-selection=<Shift-Command-Key-F3>
replace=<Command-Key-r>
goto-line=<Command-Key-j>
smart-backspace=<Key-BackSpace>
newline-and-indent=<Key-Return> <Key-KP_Enter>
smart-indent=<Key-Tab>
indent-region=<Command-Key-bracketright>
dedent-region=<Command-Key-bracketleft>
comment-region=<Control-Key-3>
uncomment-region=<Control-Key-4>
tabify-region=<Control-Key-5>
untabify-region=<Control-Key-6>
toggle-tabs=<Control-Key-t>
change-indentwidth=<Control-Key-u>
del-word-left=<Control-Key-BackSpace>
del-word-right=<Control-Key-Delete>
force-open-completions= <Control-Key-space>
expand-word= <Option-Key-slash>
force-open-calltip= <Control-Key-backslash>
format-paragraph= <Option-Key-q>
flash-paren= <Control-Key-0>
run-module= <Key-F5>
run-custom= <Shift-Key-F5>
check-module= <Option-Key-x>
zoom-height= <Option-Key-0>
[IDLE Classic OSX]
toggle-tabs = <Control-Key-t>
interrupt-execution = <Control-Key-c>
untabify-region = <Control-Key-6>
remove-selection = <Key-Escape>
print-window = <Command-Key-p>
replace = <Command-Key-r>
goto-line = <Command-Key-j>
plain-newline-and-indent = <Control-Key-j>
history-previous = <Control-Key-p>
beginning-of-line = <Control-Key-Left>
end-of-line = <Control-Key-Right>
comment-region = <Control-Key-3>
redo = <Shift-Command-Key-Z>
close-window = <Command-Key-w>
restart-shell = <Control-Key-F6>
save-window-as-file = <Shift-Command-Key-S>
close-all-windows = <Command-Key-q>
view-restart = <Key-F6>
tabify-region = <Control-Key-5>
find-again = <Command-Key-g> <Key-F3>
find = <Command-Key-f>
toggle-auto-coloring = <Control-Key-slash>
select-all = <Command-Key-a>
smart-backspace = <Key-BackSpace>
change-indentwidth = <Control-Key-u>
do-nothing = <Control-Key-F12>
smart-indent = <Key-Tab>
center-insert = <Control-Key-l>
history-next = <Control-Key-n>
del-word-right = <Option-Key-Delete>
undo = <Command-Key-z>
save-window = <Command-Key-s>
uncomment-region = <Control-Key-4>
cut = <Command-Key-x>
find-in-files = <Command-Key-F3>
dedent-region = <Command-Key-bracketleft>
copy = <Command-Key-c>
paste = <Command-Key-v>
indent-region = <Command-Key-bracketright>
del-word-left = <Option-Key-BackSpace> <Option-Command-Key-BackSpace>
newline-and-indent = <Key-Return> <Key-KP_Enter>
end-of-file = <Control-Key-d>
open-class-browser = <Command-Key-b>
open-new-window = <Command-Key-n>
open-module = <Command-Key-m>
find-selection = <Shift-Command-Key-F3>
python-context-help = <Shift-Key-F1>
save-copy-of-window-as-file = <Option-Command-Key-s>
open-window-from-file = <Command-Key-o>
python-docs = <Key-F1>
force-open-completions= <Control-Key-space>
expand-word= <Option-Key-slash>
force-open-calltip= <Control-Key-backslash>
format-paragraph= <Option-Key-q>
flash-paren= <Control-Key-0>
run-module= <Key-F5>
run-custom= <Shift-Key-F5>
check-module= <Option-Key-x>
zoom-height= <Option-Key-0>

View File

@@ -0,0 +1,93 @@
# IDLE reads several config files to determine user preferences. This
# file is the default config file for general idle settings.
#
# When IDLE starts, it will look in
# the following two sets of files, in order:
#
# default configuration files in idlelib
# --------------------------------------
# config-main.def default general config file
# config-extensions.def default extension config file
# config-highlight.def default highlighting config file
# config-keys.def default keybinding config file
#
# user configuration files in ~/.idlerc
# -------------------------------------
# config-main.cfg user general config file
# config-extensions.cfg user extension config file
# config-highlight.cfg user highlighting config file
# config-keys.cfg user keybinding config file
#
# On Windows, the default location of the home directory ('~' above)
# depends on the version. For Windows 10, it is C:\Users\<username>.
#
# Any options the user saves through the config dialog will be saved to
# the relevant user config file. Reverting any general or extension
# setting to the default causes that entry to be wiped from the user
# file and re-read from the default file. This rule applies to each
# item, except that the three editor font items are saved as a group.
#
# User highlighting themes and keybinding sets must have (section) names
# distinct from the default names. All items are added and saved as a
# group. They are retained unless specifically deleted within the config
# dialog. Choosing one of the default themes or keysets just applies the
# relevant settings from the default file.
#
# Additional help sources are listed in the [HelpFiles] section below
# and should be viewable by a web browser (or the Windows Help viewer in
# the case of .chm files). These sources will be listed on the Help
# menu. The pattern, and two examples, are:
#
# <sequence_number = menu item;/path/to/help/source>
# 1 = IDLE;C:/Programs/Python36/Lib/idlelib/help.html
# 2 = Pillow;https://pillow.readthedocs.io/en/latest/
#
# You can't use a semi-colon in a menu item or path. The path will be
# platform specific because of path separators, drive specs etc.
#
# The default files should not be edited except to add new sections to
# config-extensions.def for added extensions. The user files should be
# modified through the Settings dialog.
[General]
editor-on-startup= 0
autosave= 0
print-command-posix=lpr %%s
print-command-win=start /min notepad /p %%s
delete-exitfunc= 1
[EditorWindow]
width= 80
height= 40
cursor-blink= 1
font= TkFixedFont
# For TkFixedFont, the actual size and boldness are obtained from tk
# and override 10 and 0. See idlelib.config.IdleConf.GetFont
font-size= 10
font-bold= 0
encoding= none
line-numbers-default= 0
[PyShell]
auto-squeeze-min-lines= 50
[Indent]
use-spaces= 1
num-spaces= 4
[Theme]
default= 1
name= IDLE Classic
name2=
# name2 set in user config-main.cfg for themes added after 2015 Oct 1
[Keys]
default= 1
name=
name2=
# name2 set in user config-main.cfg for keys added after 2016 July 1
[History]
cyclic=1
[HelpFiles]

911
.CondaPkg/env/Lib/idlelib/config.py vendored Normal file
View File

@@ -0,0 +1,911 @@
"""idlelib.config -- Manage IDLE configuration information.
The comments at the beginning of config-main.def describe the
configuration files and the design implemented to update user
configuration information. In particular, user configuration choices
which duplicate the defaults will be removed from the user's
configuration files, and if a user file becomes empty, it will be
deleted.
The configuration database maps options to values. Conceptually, the
database keys are tuples (config-type, section, item). As implemented,
there are separate dicts for default and user values. Each has
config-type keys 'main', 'extensions', 'highlight', and 'keys'. The
value for each key is a ConfigParser instance that maps section and item
to values. For 'main' and 'extensions', user values override
default values. For 'highlight' and 'keys', user sections augment the
default sections (and must, therefore, have distinct names).
Throughout this module there is an emphasis on returning usable defaults
when a problem occurs in returning a requested configuration value back to
idle. This is to allow IDLE to continue to function in spite of errors in
the retrieval of config information. When a default is returned instead of
a requested config value, a message is printed to stderr to aid in
configuration problem notification and resolution.
"""
# TODOs added Oct 2014, tjr
from configparser import ConfigParser
import os
import sys
from tkinter.font import Font
import idlelib
class InvalidConfigType(Exception): pass
class InvalidConfigSet(Exception): pass
class InvalidTheme(Exception): pass
class IdleConfParser(ConfigParser):
"""
A ConfigParser specialised for idle configuration file handling
"""
def __init__(self, cfgFile, cfgDefaults=None):
"""
cfgFile - string, fully specified configuration file name
"""
self.file = cfgFile # This is currently '' when testing.
ConfigParser.__init__(self, defaults=cfgDefaults, strict=False)
def Get(self, section, option, type=None, default=None, raw=False):
"""
Get an option value for given section/option or return default.
If type is specified, return as type.
"""
# TODO Use default as fallback, at least if not None
# Should also print Warning(file, section, option).
# Currently may raise ValueError
if not self.has_option(section, option):
return default
if type == 'bool':
return self.getboolean(section, option)
elif type == 'int':
return self.getint(section, option)
else:
return self.get(section, option, raw=raw)
def GetOptionList(self, section):
"Return a list of options for given section, else []."
if self.has_section(section):
return self.options(section)
else: #return a default value
return []
def Load(self):
"Load the configuration file from disk."
if self.file:
self.read(self.file)
class IdleUserConfParser(IdleConfParser):
"""
IdleConfigParser specialised for user configuration handling.
"""
def SetOption(self, section, option, value):
"""Return True if option is added or changed to value, else False.
Add section if required. False means option already had value.
"""
if self.has_option(section, option):
if self.get(section, option) == value:
return False
else:
self.set(section, option, value)
return True
else:
if not self.has_section(section):
self.add_section(section)
self.set(section, option, value)
return True
def RemoveOption(self, section, option):
"""Return True if option is removed from section, else False.
False if either section does not exist or did not have option.
"""
if self.has_section(section):
return self.remove_option(section, option)
return False
def AddSection(self, section):
"If section doesn't exist, add it."
if not self.has_section(section):
self.add_section(section)
def RemoveEmptySections(self):
"Remove any sections that have no options."
for section in self.sections():
if not self.GetOptionList(section):
self.remove_section(section)
def IsEmpty(self):
"Return True if no sections after removing empty sections."
self.RemoveEmptySections()
return not self.sections()
def Save(self):
"""Update user configuration file.
If self not empty after removing empty sections, write the file
to disk. Otherwise, remove the file from disk if it exists.
"""
fname = self.file
if fname and fname[0] != '#':
if not self.IsEmpty():
try:
cfgFile = open(fname, 'w')
except OSError:
os.unlink(fname)
cfgFile = open(fname, 'w')
with cfgFile:
self.write(cfgFile)
elif os.path.exists(self.file):
os.remove(self.file)
class IdleConf:
"""Hold config parsers for all idle config files in singleton instance.
Default config files, self.defaultCfg --
for config_type in self.config_types:
(idle install dir)/config-{config-type}.def
User config files, self.userCfg --
for config_type in self.config_types:
(user home dir)/.idlerc/config-{config-type}.cfg
"""
def __init__(self, _utest=False):
self.config_types = ('main', 'highlight', 'keys', 'extensions')
self.defaultCfg = {}
self.userCfg = {}
self.cfg = {} # TODO use to select userCfg vs defaultCfg
# self.blink_off_time = <first editor text>['insertofftime']
# See https:/bugs.python.org/issue4630, msg356516.
if not _utest:
self.CreateConfigHandlers()
self.LoadCfgFiles()
def CreateConfigHandlers(self):
"Populate default and user config parser dictionaries."
idledir = os.path.dirname(__file__)
self.userdir = userdir = '' if idlelib.testing else self.GetUserCfgDir()
for cfg_type in self.config_types:
self.defaultCfg[cfg_type] = IdleConfParser(
os.path.join(idledir, f'config-{cfg_type}.def'))
self.userCfg[cfg_type] = IdleUserConfParser(
os.path.join(userdir or '#', f'config-{cfg_type}.cfg'))
def GetUserCfgDir(self):
"""Return a filesystem directory for storing user config files.
Creates it if required.
"""
cfgDir = '.idlerc'
userDir = os.path.expanduser('~')
if userDir != '~': # expanduser() found user home dir
if not os.path.exists(userDir):
if not idlelib.testing:
warn = ('\n Warning: os.path.expanduser("~") points to\n ' +
userDir + ',\n but the path does not exist.')
try:
print(warn, file=sys.stderr)
except OSError:
pass
userDir = '~'
if userDir == "~": # still no path to home!
# traditionally IDLE has defaulted to os.getcwd(), is this adequate?
userDir = os.getcwd()
userDir = os.path.join(userDir, cfgDir)
if not os.path.exists(userDir):
try:
os.mkdir(userDir)
except OSError:
if not idlelib.testing:
warn = ('\n Warning: unable to create user config directory\n' +
userDir + '\n Check path and permissions.\n Exiting!\n')
try:
print(warn, file=sys.stderr)
except OSError:
pass
raise SystemExit
# TODO continue without userDIr instead of exit
return userDir
def GetOption(self, configType, section, option, default=None, type=None,
warn_on_default=True, raw=False):
"""Return a value for configType section option, or default.
If type is not None, return a value of that type. Also pass raw
to the config parser. First try to return a valid value
(including type) from a user configuration. If that fails, try
the default configuration. If that fails, return default, with a
default of None.
Warn if either user or default configurations have an invalid value.
Warn if default is returned and warn_on_default is True.
"""
try:
if self.userCfg[configType].has_option(section, option):
return self.userCfg[configType].Get(section, option,
type=type, raw=raw)
except ValueError:
warning = ('\n Warning: config.py - IdleConf.GetOption -\n'
' invalid %r value for configuration option %r\n'
' from section %r: %r' %
(type, option, section,
self.userCfg[configType].Get(section, option, raw=raw)))
_warn(warning, configType, section, option)
try:
if self.defaultCfg[configType].has_option(section,option):
return self.defaultCfg[configType].Get(
section, option, type=type, raw=raw)
except ValueError:
pass
#returning default, print warning
if warn_on_default:
warning = ('\n Warning: config.py - IdleConf.GetOption -\n'
' problem retrieving configuration option %r\n'
' from section %r.\n'
' returning default value: %r' %
(option, section, default))
_warn(warning, configType, section, option)
return default
def SetOption(self, configType, section, option, value):
"""Set section option to value in user config file."""
self.userCfg[configType].SetOption(section, option, value)
def GetSectionList(self, configSet, configType):
"""Return sections for configSet configType configuration.
configSet must be either 'user' or 'default'
configType must be in self.config_types.
"""
if not (configType in self.config_types):
raise InvalidConfigType('Invalid configType specified')
if configSet == 'user':
cfgParser = self.userCfg[configType]
elif configSet == 'default':
cfgParser=self.defaultCfg[configType]
else:
raise InvalidConfigSet('Invalid configSet specified')
return cfgParser.sections()
def GetHighlight(self, theme, element):
"""Return dict of theme element highlight colors.
The keys are 'foreground' and 'background'. The values are
tkinter color strings for configuring backgrounds and tags.
"""
cfg = ('default' if self.defaultCfg['highlight'].has_section(theme)
else 'user')
theme_dict = self.GetThemeDict(cfg, theme)
fore = theme_dict[element + '-foreground']
if element == 'cursor':
element = 'normal'
back = theme_dict[element + '-background']
return {"foreground": fore, "background": back}
def GetThemeDict(self, type, themeName):
"""Return {option:value} dict for elements in themeName.
type - string, 'default' or 'user' theme type
themeName - string, theme name
Values are loaded over ultimate fallback defaults to guarantee
that all theme elements are present in a newly created theme.
"""
if type == 'user':
cfgParser = self.userCfg['highlight']
elif type == 'default':
cfgParser = self.defaultCfg['highlight']
else:
raise InvalidTheme('Invalid theme type specified')
# Provide foreground and background colors for each theme
# element (other than cursor) even though some values are not
# yet used by idle, to allow for their use in the future.
# Default values are generally black and white.
# TODO copy theme from a class attribute.
theme ={'normal-foreground':'#000000',
'normal-background':'#ffffff',
'keyword-foreground':'#000000',
'keyword-background':'#ffffff',
'builtin-foreground':'#000000',
'builtin-background':'#ffffff',
'comment-foreground':'#000000',
'comment-background':'#ffffff',
'string-foreground':'#000000',
'string-background':'#ffffff',
'definition-foreground':'#000000',
'definition-background':'#ffffff',
'hilite-foreground':'#000000',
'hilite-background':'gray',
'break-foreground':'#ffffff',
'break-background':'#000000',
'hit-foreground':'#ffffff',
'hit-background':'#000000',
'error-foreground':'#ffffff',
'error-background':'#000000',
'context-foreground':'#000000',
'context-background':'#ffffff',
'linenumber-foreground':'#000000',
'linenumber-background':'#ffffff',
#cursor (only foreground can be set)
'cursor-foreground':'#000000',
#shell window
'stdout-foreground':'#000000',
'stdout-background':'#ffffff',
'stderr-foreground':'#000000',
'stderr-background':'#ffffff',
'console-foreground':'#000000',
'console-background':'#ffffff',
}
for element in theme:
if not (cfgParser.has_option(themeName, element) or
# Skip warning for new elements.
element.startswith(('context-', 'linenumber-'))):
# Print warning that will return a default color
warning = ('\n Warning: config.IdleConf.GetThemeDict'
' -\n problem retrieving theme element %r'
'\n from theme %r.\n'
' returning default color: %r' %
(element, themeName, theme[element]))
_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 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
[Theme]
default= 1
name= IDLE Classic
name2=
[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 = False,
'name2' may still be set, but it is ignored.
"""
cfgname = 'highlight' if section == 'Theme' else 'keys'
default = self.GetOption('main', section, 'default',
type='bool', default=True)
name = ''
if default:
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 Modern Unix'
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
and optionally only editor or shell extensions.
If active_only False, return all extensions.
"""
extns = self.RemoveKeyBindNames(
self.GetSectionList('default', 'extensions'))
userExtns = self.RemoveKeyBindNames(
self.GetSectionList('user', 'extensions'))
for extn in userExtns:
if extn not in extns: #user has added own extension
extns.append(extn)
for extn in ('AutoComplete','CodeContext',
'FormatParagraph','ParenMatch'):
extns.remove(extn)
# specific exclusions because we are storing config for mainlined old
# extensions in config-extensions.def for backward compatibility
if active_only:
activeExtns = []
for extn in extns:
if self.GetOption('extensions', extn, 'enable', default=True,
type='bool'):
#the extension is enabled
if editor_only or shell_only: # TODO both True contradict
if editor_only:
option = "enable_editor"
else:
option = "enable_shell"
if self.GetOption('extensions', extn,option,
default=True, type='bool',
warn_on_default=False):
activeExtns.append(extn)
else:
activeExtns.append(extn)
return activeExtns
else:
return extns
def RemoveKeyBindNames(self, extnNameList):
"Return extnNameList with keybinding section names removed."
return [n for n in extnNameList if not n.endswith(('_bindings', '_cfgBindings'))]
def GetExtnNameForEvent(self, virtualEvent):
"""Return the name of the extension binding virtualEvent, or None.
virtualEvent - string, name of the virtual event to test for,
without the enclosing '<< >>'
"""
extName = None
vEvent = '<<' + virtualEvent + '>>'
for extn in self.GetExtensions(active_only=0):
for event in self.GetExtensionKeys(extn):
if event == vEvent:
extName = extn # TODO return here?
return extName
def GetExtensionKeys(self, extensionName):
"""Return dict: {configurable extensionName event : active keybinding}.
Events come from default config extension_cfgBindings section.
Keybindings come from GetCurrentKeySet() active key dict,
where previously used bindings are disabled.
"""
keysName = extensionName + '_cfgBindings'
activeKeys = self.GetCurrentKeySet()
extKeys = {}
if self.defaultCfg['extensions'].has_section(keysName):
eventNames = self.defaultCfg['extensions'].GetOptionList(keysName)
for eventName in eventNames:
event = '<<' + eventName + '>>'
binding = activeKeys[event]
extKeys[event] = binding
return extKeys
def __GetRawExtensionKeys(self,extensionName):
"""Return dict {configurable extensionName event : keybinding list}.
Events come from default config extension_cfgBindings section.
Keybindings list come from the splitting of GetOption, which
tries user config before default config.
"""
keysName = extensionName+'_cfgBindings'
extKeys = {}
if self.defaultCfg['extensions'].has_section(keysName):
eventNames = self.defaultCfg['extensions'].GetOptionList(keysName)
for eventName in eventNames:
binding = self.GetOption(
'extensions', keysName, eventName, default='').split()
event = '<<' + eventName + '>>'
extKeys[event] = binding
return extKeys
def GetExtensionBindings(self, extensionName):
"""Return dict {extensionName event : active or defined keybinding}.
Augment self.GetExtensionKeys(extensionName) with mapping of non-
configurable events (from default config) to GetOption splits,
as in self.__GetRawExtensionKeys.
"""
bindsName = extensionName + '_bindings'
extBinds = self.GetExtensionKeys(extensionName)
#add the non-configurable bindings
if self.defaultCfg['extensions'].has_section(bindsName):
eventNames = self.defaultCfg['extensions'].GetOptionList(bindsName)
for eventName in eventNames:
binding = self.GetOption(
'extensions', bindsName, eventName, default='').split()
event = '<<' + eventName + '>>'
extBinds[event] = binding
return extBinds
def GetKeyBinding(self, keySetName, eventStr):
"""Return the keybinding list for keySetName eventStr.
keySetName - name of key binding set (config-keys section).
eventStr - virtual event, including brackets, as in '<<event>>'.
"""
eventName = eventStr[2:-2] #trim off the angle brackets
binding = self.GetOption('keys', keySetName, eventName, default='',
warn_on_default=False).split()
return binding
def GetCurrentKeySet(self):
"Return CurrentKeys with 'darwin' modifications."
result = self.GetKeySet(self.CurrentKeys())
if sys.platform == "darwin":
# macOS (OS X) Tk variants do not support the "Alt"
# keyboard modifier. Replace it with "Option".
# TODO (Ned?): the "Option" modifier does not work properly
# for Cocoa Tk and XQuartz Tk so we should not use it
# in the default 'OSX' keyset.
for k, v in result.items():
v2 = [ x.replace('<Alt-', '<Option-') for x in v ]
if v != v2:
result[k] = v2
return result
def GetKeySet(self, keySetName):
"""Return event-key dict for keySetName core plus active extensions.
If a binding defined in an extension is already in use, the
extension binding is disabled by being set to ''
"""
keySet = self.GetCoreKeys(keySetName)
activeExtns = self.GetExtensions(active_only=1)
for extn in activeExtns:
extKeys = self.__GetRawExtensionKeys(extn)
if extKeys: #the extension defines keybindings
for event in extKeys:
if extKeys[event] in keySet.values():
#the binding is already in use
extKeys[event] = '' #disable this binding
keySet[event] = extKeys[event] #add binding
return keySet
def IsCoreBinding(self, virtualEvent):
"""Return True if the virtual event is one of the core idle key events.
virtualEvent - string, name of the virtual event to test for,
without the enclosing '<< >>'
"""
return ('<<'+virtualEvent+'>>') in self.GetCoreKeys()
# 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.
'<<force-open-completions>>', '<<expand-word>>',
'<<force-open-calltip>>', '<<flash-paren>>', '<<format-paragraph>>',
'<<run-module>>', '<<check-module>>', '<<zoom-height>>',
'<<run-custom>>',
}
def GetCoreKeys(self, keySetName=None):
"""Return dict of core virtual-key keybindings for keySetName.
The default keySetName None corresponds to the keyBindings base
dict. If keySetName is not None, bindings from the config
file(s) are loaded _over_ these defaults, so if there is a
problem getting any core binding there will be an 'ultimate last
resort fallback' to the CUA-ish bindings defined here.
"""
keyBindings={
'<<copy>>': ['<Control-c>', '<Control-C>'],
'<<cut>>': ['<Control-x>', '<Control-X>'],
'<<paste>>': ['<Control-v>', '<Control-V>'],
'<<beginning-of-line>>': ['<Control-a>', '<Home>'],
'<<center-insert>>': ['<Control-l>'],
'<<close-all-windows>>': ['<Control-q>'],
'<<close-window>>': ['<Alt-F4>'],
'<<do-nothing>>': ['<Control-x>'],
'<<end-of-file>>': ['<Control-d>'],
'<<python-docs>>': ['<F1>'],
'<<python-context-help>>': ['<Shift-F1>'],
'<<history-next>>': ['<Alt-n>'],
'<<history-previous>>': ['<Alt-p>'],
'<<interrupt-execution>>': ['<Control-c>'],
'<<view-restart>>': ['<F6>'],
'<<restart-shell>>': ['<Control-F6>'],
'<<open-class-browser>>': ['<Alt-c>'],
'<<open-module>>': ['<Alt-m>'],
'<<open-new-window>>': ['<Control-n>'],
'<<open-window-from-file>>': ['<Control-o>'],
'<<plain-newline-and-indent>>': ['<Control-j>'],
'<<print-window>>': ['<Control-p>'],
'<<redo>>': ['<Control-y>'],
'<<remove-selection>>': ['<Escape>'],
'<<save-copy-of-window-as-file>>': ['<Alt-Shift-S>'],
'<<save-window-as-file>>': ['<Alt-s>'],
'<<save-window>>': ['<Control-s>'],
'<<select-all>>': ['<Alt-a>'],
'<<toggle-auto-coloring>>': ['<Control-slash>'],
'<<undo>>': ['<Control-z>'],
'<<find-again>>': ['<Control-g>', '<F3>'],
'<<find-in-files>>': ['<Alt-F3>'],
'<<find-selection>>': ['<Control-F3>'],
'<<find>>': ['<Control-f>'],
'<<replace>>': ['<Control-h>'],
'<<goto-line>>': ['<Alt-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>>': ['<Alt-Key-3>'],
'<<uncomment-region>>': ['<Alt-Key-4>'],
'<<tabify-region>>': ['<Alt-Key-5>'],
'<<untabify-region>>': ['<Alt-Key-6>'],
'<<toggle-tabs>>': ['<Alt-Key-t>'],
'<<change-indentwidth>>': ['<Alt-Key-u>'],
'<<del-word-left>>': ['<Control-Key-BackSpace>'],
'<<del-word-right>>': ['<Control-Key-Delete>'],
'<<force-open-completions>>': ['<Control-Key-space>'],
'<<expand-word>>': ['<Alt-Key-slash>'],
'<<force-open-calltip>>': ['<Control-Key-backslash>'],
'<<flash-paren>>': ['<Control-Key-0>'],
'<<format-paragraph>>': ['<Alt-Key-q>'],
'<<run-module>>': ['<Key-F5>'],
'<<run-custom>>': ['<Shift-Key-F5>'],
'<<check-module>>': ['<Alt-Key-x>'],
'<<zoom-height>>': ['<Alt-Key-2>'],
}
if keySetName:
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
# Otherwise return default in keyBindings.
elif event not in self.former_extension_events:
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):
"""Return list of extra help sources from a given configSet.
Valid configSets are 'user' or 'default'. Return a list of tuples of
the form (menu_item , path_to_help_file , option), or return the empty
list. 'option' is the sequence number of the help resource. 'option'
values determine the position of the menu items on the Help menu,
therefore the returned list must be sorted by 'option'.
"""
helpSources = []
if configSet == 'user':
cfgParser = self.userCfg['main']
elif configSet == 'default':
cfgParser = self.defaultCfg['main']
else:
raise InvalidConfigSet('Invalid configSet specified')
options=cfgParser.GetOptionList('HelpFiles')
for option in options:
value=cfgParser.Get('HelpFiles', option, default=';')
if value.find(';') == -1: #malformed config entry with no ';'
menuItem = '' #make these empty
helpPath = '' #so value won't be added to list
else: #config entry contains ';' as expected
value=value.split(';')
menuItem=value[0].strip()
helpPath=value[1].strip()
if menuItem and helpPath: #neither are empty strings
helpSources.append( (menuItem,helpPath,option) )
helpSources.sort(key=lambda x: x[2])
return helpSources
def GetAllExtraHelpSourcesList(self):
"""Return a list of the details of all additional help sources.
Tuples in the list are those of GetExtraHelpSourceList.
"""
allHelpSources = (self.GetExtraHelpSourceList('default') +
self.GetExtraHelpSourceList('user') )
return allHelpSources
def GetFont(self, root, configType, section):
"""Retrieve a font from configuration (font, font-size, font-bold)
Intercept the special value 'TkFixedFont' and substitute
the actual font, factoring in some tweaks if needed for
appearance sakes.
The 'root' parameter can normally be any valid Tkinter widget.
Return a tuple (family, size, weight) suitable for passing
to tkinter.Font
"""
family = self.GetOption(configType, section, 'font', default='courier')
size = self.GetOption(configType, section, 'font-size', type='int',
default='10')
bold = self.GetOption(configType, section, 'font-bold', default=0,
type='bool')
if (family == 'TkFixedFont'):
f = Font(name='TkFixedFont', exists=True, root=root)
actualFont = Font.actual(f)
family = actualFont['family']
size = actualFont['size']
if size <= 0:
size = 10 # if font in pixels, ignore actual size
bold = actualFont['weight'] == 'bold'
return (family, size, 'bold' if bold else 'normal')
def LoadCfgFiles(self):
"Load all configuration files."
for key in self.defaultCfg:
self.defaultCfg[key].Load()
self.userCfg[key].Load() #same keys
def SaveUserCfgFiles(self):
"Write all loaded user configuration files to disk."
for key in self.userCfg:
self.userCfg[key].Save()
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)
class ConfigChanges(dict):
"""Manage a user's proposed configuration option changes.
Names used across multiple methods:
page -- one of the 4 top-level dicts representing a
.idlerc/config-x.cfg file.
config_type -- name of a page.
section -- a section within a page/file.
option -- name of an option within a section.
value -- value for the option.
Methods
add_option: Add option and value to changes.
save_option: Save option and value to config parser.
save_all: Save all the changes to the config parser and file.
delete_section: If section exists,
delete from changes, userCfg, and file.
clear: Clear all changes by clearing each page.
"""
def __init__(self):
"Create a page for each configuration file"
self.pages = [] # List of unhashable dicts.
for config_type in idleConf.config_types:
self[config_type] = {}
self.pages.append(self[config_type])
def add_option(self, config_type, section, item, value):
"Add item/value pair for config_type and section."
page = self[config_type]
value = str(value) # Make sure we use a string.
if section not in page:
page[section] = {}
page[section][item] = value
@staticmethod
def save_option(config_type, section, item, value):
"""Return True if the configuration value was added or changed.
Helper for save_all.
"""
if idleConf.defaultCfg[config_type].has_option(section, item):
if idleConf.defaultCfg[config_type].Get(section, item) == value:
# The setting equals a default setting, remove it from user cfg.
return idleConf.userCfg[config_type].RemoveOption(section, item)
# If we got here, set the option.
return idleConf.userCfg[config_type].SetOption(section, item, value)
def save_all(self):
"""Save configuration changes to the user config file.
Clear self in preparation for additional changes.
Return changed for testing.
"""
idleConf.userCfg['main'].Save()
changed = False
for config_type in self:
cfg_type_changed = False
page = self[config_type]
for section in page:
if section == 'HelpFiles': # Remove it for replacement.
idleConf.userCfg['main'].remove_section('HelpFiles')
cfg_type_changed = True
for item, value in page[section].items():
if self.save_option(config_type, section, item, value):
cfg_type_changed = True
if cfg_type_changed:
idleConf.userCfg[config_type].Save()
changed = True
for config_type in ['keys', 'highlight']:
# Save these even if unchanged!
idleConf.userCfg[config_type].Save()
self.clear()
# ConfigDialog caller must add the following call
# self.save_all_changed_extensions() # Uses a different mechanism.
return changed
def delete_section(self, config_type, section):
"""Delete a section from self, userCfg, and file.
Used to delete custom themes and keysets.
"""
if section in self[config_type]:
del self[config_type][section]
configpage = idleConf.userCfg[config_type]
configpage.remove_section(section)
configpage.Save()
def clear(self):
"""Clear all 4 pages.
Called in save_all after saving to idleConf.
XXX Mark window *title* when there are changes; unmark here.
"""
for page in self.pages:
page.clear()
# TODO Revise test output, write expanded unittest
def _dump(): # htest # (not really, but ignore in coverage)
from zlib import crc32
line, crc = 0, 0
def sprint(obj):
global line, crc
txt = str(obj)
line += 1
crc = crc32(txt.encode(encoding='utf-8'), crc)
print(txt)
#print('***', line, crc, '***') # Uncomment for diagnosis.
def dumpCfg(cfg):
print('\n', cfg, '\n') # Cfg has variable '0xnnnnnnnn' address.
for key in sorted(cfg.keys()):
sections = cfg[key].sections()
sprint(key)
sprint(sections)
for section in sections:
options = cfg[key].options(section)
sprint(section)
sprint(options)
for option in options:
sprint(option + ' = ' + cfg[key].Get(section, option))
dumpCfg(idleConf.defaultCfg)
dumpCfg(idleConf.userCfg)
print('\nlines = ', line, ', crc = ', crc, sep='')
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_config', verbosity=2, exit=False)
# Run revised _dump() as htest?

354
.CondaPkg/env/Lib/idlelib/config_key.py vendored Normal file
View File

@@ -0,0 +1,354 @@
"""
Dialog for building Tkinter accelerator key bindings
"""
from tkinter import Toplevel, Listbox, StringVar, TclError
from tkinter.ttk import Frame, Button, Checkbutton, Entry, Label, Scrollbar
from tkinter import messagebox
from tkinter.simpledialog import _setup_dialog
import string
import sys
FUNCTION_KEYS = ('F1', 'F2' ,'F3' ,'F4' ,'F5' ,'F6',
'F7', 'F8' ,'F9' ,'F10' ,'F11' ,'F12')
ALPHANUM_KEYS = tuple(string.ascii_lowercase + string.digits)
PUNCTUATION_KEYS = tuple('~!@#%^&*()_-+={}[]|;:,.<>/?')
WHITESPACE_KEYS = ('Tab', 'Space', 'Return')
EDIT_KEYS = ('BackSpace', 'Delete', 'Insert')
MOVE_KEYS = ('Home', 'End', 'Page Up', 'Page Down', 'Left Arrow',
'Right Arrow', 'Up Arrow', 'Down Arrow')
AVAILABLE_KEYS = (ALPHANUM_KEYS + PUNCTUATION_KEYS + FUNCTION_KEYS +
WHITESPACE_KEYS + EDIT_KEYS + MOVE_KEYS)
def translate_key(key, modifiers):
"Translate from keycap symbol to the Tkinter keysym."
mapping = {'Space':'space',
'~':'asciitilde', '!':'exclam', '@':'at', '#':'numbersign',
'%':'percent', '^':'asciicircum', '&':'ampersand',
'*':'asterisk', '(':'parenleft', ')':'parenright',
'_':'underscore', '-':'minus', '+':'plus', '=':'equal',
'{':'braceleft', '}':'braceright',
'[':'bracketleft', ']':'bracketright', '|':'bar',
';':'semicolon', ':':'colon', ',':'comma', '.':'period',
'<':'less', '>':'greater', '/':'slash', '?':'question',
'Page Up':'Prior', 'Page Down':'Next',
'Left Arrow':'Left', 'Right Arrow':'Right',
'Up Arrow':'Up', 'Down Arrow': 'Down', 'Tab':'Tab'}
key = mapping.get(key, key)
if 'Shift' in modifiers and key in string.ascii_lowercase:
key = key.upper()
return f'Key-{key}'
class GetKeysFrame(Frame):
# Dialog title for invalid key sequence
keyerror_title = 'Key Sequence Error'
def __init__(self, parent, action, current_key_sequences):
"""
parent - parent of this dialog
action - the name of the virtual event these keys will be
mapped to
current_key_sequences - a list of all key sequence lists
currently mapped to virtual events, for overlap checking
"""
super().__init__(parent)
self['borderwidth'] = 2
self['relief'] = 'sunken'
self.parent = parent
self.action = action
self.current_key_sequences = current_key_sequences
self.result = ''
self.key_string = StringVar(self)
self.key_string.set('')
# Set self.modifiers, self.modifier_label.
self.set_modifiers_for_platform()
self.modifier_vars = []
for modifier in self.modifiers:
variable = StringVar(self)
variable.set('')
self.modifier_vars.append(variable)
self.advanced = False
self.create_widgets()
def showerror(self, *args, **kwargs):
# Make testing easier. Replace in #30751.
messagebox.showerror(*args, **kwargs)
def create_widgets(self):
# Basic entry key sequence.
self.frame_keyseq_basic = Frame(self, name='keyseq_basic')
self.frame_keyseq_basic.grid(row=0, column=0, sticky='nsew',
padx=5, pady=5)
basic_title = Label(self.frame_keyseq_basic,
text=f"New keys for '{self.action}' :")
basic_title.pack(anchor='w')
basic_keys = Label(self.frame_keyseq_basic, justify='left',
textvariable=self.key_string, relief='groove',
borderwidth=2)
basic_keys.pack(ipadx=5, ipady=5, fill='x')
# Basic entry controls.
self.frame_controls_basic = Frame(self)
self.frame_controls_basic.grid(row=1, column=0, sticky='nsew', padx=5)
# Basic entry modifiers.
self.modifier_checkbuttons = {}
column = 0
for modifier, variable in zip(self.modifiers, self.modifier_vars):
label = self.modifier_label.get(modifier, modifier)
check = Checkbutton(self.frame_controls_basic,
command=self.build_key_string, text=label,
variable=variable, onvalue=modifier, offvalue='')
check.grid(row=0, column=column, padx=2, sticky='w')
self.modifier_checkbuttons[modifier] = check
column += 1
# Basic entry help text.
help_basic = Label(self.frame_controls_basic, justify='left',
text="Select the desired modifier keys\n"+
"above, and the final key from the\n"+
"list on the right.\n\n" +
"Use upper case Symbols when using\n" +
"the Shift modifier. (Letters will be\n" +
"converted automatically.)")
help_basic.grid(row=1, column=0, columnspan=4, padx=2, sticky='w')
# Basic entry key list.
self.list_keys_final = Listbox(self.frame_controls_basic, width=15,
height=10, selectmode='single')
self.list_keys_final.insert('end', *AVAILABLE_KEYS)
self.list_keys_final.bind('<ButtonRelease-1>', self.final_key_selected)
self.list_keys_final.grid(row=0, column=4, rowspan=4, sticky='ns')
scroll_keys_final = Scrollbar(self.frame_controls_basic,
orient='vertical',
command=self.list_keys_final.yview)
self.list_keys_final.config(yscrollcommand=scroll_keys_final.set)
scroll_keys_final.grid(row=0, column=5, rowspan=4, sticky='ns')
self.button_clear = Button(self.frame_controls_basic,
text='Clear Keys',
command=self.clear_key_seq)
self.button_clear.grid(row=2, column=0, columnspan=4)
# Advanced entry key sequence.
self.frame_keyseq_advanced = Frame(self, name='keyseq_advanced')
self.frame_keyseq_advanced.grid(row=0, column=0, sticky='nsew',
padx=5, pady=5)
advanced_title = Label(self.frame_keyseq_advanced, justify='left',
text=f"Enter new binding(s) for '{self.action}' :\n" +
"(These bindings will not be checked for validity!)")
advanced_title.pack(anchor='w')
self.advanced_keys = Entry(self.frame_keyseq_advanced,
textvariable=self.key_string)
self.advanced_keys.pack(fill='x')
# Advanced entry help text.
self.frame_help_advanced = Frame(self)
self.frame_help_advanced.grid(row=1, column=0, sticky='nsew', padx=5)
help_advanced = Label(self.frame_help_advanced, justify='left',
text="Key bindings are specified using Tkinter keysyms as\n"+
"in these samples: <Control-f>, <Shift-F2>, <F12>,\n"
"<Control-space>, <Meta-less>, <Control-Alt-Shift-X>.\n"
"Upper case is used when the Shift modifier is present!\n\n" +
"'Emacs style' multi-keystroke bindings are specified as\n" +
"follows: <Control-x><Control-y>, where the first key\n" +
"is the 'do-nothing' keybinding.\n\n" +
"Multiple separate bindings for one action should be\n"+
"separated by a space, eg., <Alt-v> <Meta-v>." )
help_advanced.grid(row=0, column=0, sticky='nsew')
# Switch between basic and advanced.
self.button_level = Button(self, command=self.toggle_level,
text='<< Basic Key Binding Entry')
self.button_level.grid(row=2, column=0, stick='ew', padx=5, pady=5)
self.toggle_level()
def set_modifiers_for_platform(self):
"""Determine list of names of key modifiers for this platform.
The names are used to build Tk bindings -- it doesn't matter if the
keyboard has these keys; it matters if Tk understands them. The
order is also important: key binding equality depends on it, so
config-keys.def must use the same ordering.
"""
if sys.platform == "darwin":
self.modifiers = ['Shift', 'Control', 'Option', 'Command']
else:
self.modifiers = ['Control', 'Alt', 'Shift']
self.modifier_label = {'Control': 'Ctrl'} # Short name.
def toggle_level(self):
"Toggle between basic and advanced keys."
if self.button_level.cget('text').startswith('Advanced'):
self.clear_key_seq()
self.button_level.config(text='<< Basic Key Binding Entry')
self.frame_keyseq_advanced.lift()
self.frame_help_advanced.lift()
self.advanced_keys.focus_set()
self.advanced = True
else:
self.clear_key_seq()
self.button_level.config(text='Advanced Key Binding Entry >>')
self.frame_keyseq_basic.lift()
self.frame_controls_basic.lift()
self.advanced = False
def final_key_selected(self, event=None):
"Handler for clicking on key in basic settings list."
self.build_key_string()
def build_key_string(self):
"Create formatted string of modifiers plus the key."
keylist = modifiers = self.get_modifiers()
final_key = self.list_keys_final.get('anchor')
if final_key:
final_key = translate_key(final_key, modifiers)
keylist.append(final_key)
self.key_string.set(f"<{'-'.join(keylist)}>")
def get_modifiers(self):
"Return ordered list of modifiers that have been selected."
mod_list = [variable.get() for variable in self.modifier_vars]
return [mod for mod in mod_list if mod]
def clear_key_seq(self):
"Clear modifiers and keys selection."
self.list_keys_final.select_clear(0, 'end')
self.list_keys_final.yview('moveto', '0.0')
for variable in self.modifier_vars:
variable.set('')
self.key_string.set('')
def ok(self):
self.result = ''
keys = self.key_string.get().strip()
if not keys:
self.showerror(title=self.keyerror_title, parent=self,
message="No key specified.")
return
if (self.advanced or self.keys_ok(keys)) and self.bind_ok(keys):
self.result = keys
return
def keys_ok(self, keys):
"""Validity check on user's 'basic' keybinding selection.
Doesn't check the string produced by the advanced dialog because
'modifiers' isn't set.
"""
final_key = self.list_keys_final.get('anchor')
modifiers = self.get_modifiers()
title = self.keyerror_title
key_sequences = [key for keylist in self.current_key_sequences
for key in keylist]
if not keys.endswith('>'):
self.showerror(title, parent=self,
message='Missing the final Key')
elif (not modifiers
and final_key not in FUNCTION_KEYS + MOVE_KEYS):
self.showerror(title=title, parent=self,
message='No modifier key(s) specified.')
elif (modifiers == ['Shift']) \
and (final_key not in
FUNCTION_KEYS + MOVE_KEYS + ('Tab', 'Space')):
msg = 'The shift modifier by itself may not be used with'\
' this key symbol.'
self.showerror(title=title, parent=self, message=msg)
elif keys in key_sequences:
msg = 'This key combination is already in use.'
self.showerror(title=title, parent=self, message=msg)
else:
return True
return False
def bind_ok(self, keys):
"Return True if Tcl accepts the new keys else show message."
try:
binding = self.bind(keys, lambda: None)
except TclError as err:
self.showerror(
title=self.keyerror_title, parent=self,
message=(f'The entered key sequence is not accepted.\n\n'
f'Error: {err}'))
return False
else:
self.unbind(keys, binding)
return True
class GetKeysWindow(Toplevel):
def __init__(self, parent, title, action, current_key_sequences,
*, _htest=False, _utest=False):
"""
parent - parent of this dialog
title - string which is the title of the popup dialog
action - string, the name of the virtual event these keys will be
mapped to
current_key_sequences - list, a list of all key sequence lists
currently mapped to virtual events, for overlap checking
_htest - bool, change box location when running htest
_utest - bool, do not wait when running unittest
"""
super().__init__(parent)
self.withdraw() # Hide while setting geometry.
self['borderwidth'] = 5
self.resizable(height=False, width=False)
# Needed for winfo_reqwidth().
self.update_idletasks()
# Center dialog over parent (or below htest box).
x = (parent.winfo_rootx() +
(parent.winfo_width()//2 - self.winfo_reqwidth()//2))
y = (parent.winfo_rooty() +
((parent.winfo_height()//2 - self.winfo_reqheight()//2)
if not _htest else 150))
self.geometry(f"+{x}+{y}")
self.title(title)
self.frame = frame = GetKeysFrame(self, action, current_key_sequences)
self.protocol("WM_DELETE_WINDOW", self.cancel)
frame_buttons = Frame(self)
self.button_ok = Button(frame_buttons, text='OK',
width=8, command=self.ok)
self.button_cancel = Button(frame_buttons, text='Cancel',
width=8, command=self.cancel)
self.button_ok.grid(row=0, column=0, padx=5, pady=5)
self.button_cancel.grid(row=0, column=1, padx=5, pady=5)
frame.pack(side='top', expand=True, fill='both')
frame_buttons.pack(side='bottom', fill='x')
self.transient(parent)
_setup_dialog(self)
self.grab_set()
if not _utest:
self.deiconify() # Geometry set, unhide.
self.wait_window()
@property
def result(self):
return self.frame.result
@result.setter
def result(self, value):
self.frame.result = value
def ok(self, event=None):
self.frame.ok()
self.grab_release()
self.destroy()
def cancel(self, event=None):
self.result = ''
self.grab_release()
self.destroy()
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_config_key', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(GetKeysDialog)

2414
.CondaPkg/env/Lib/idlelib/configdialog.py vendored Normal file

File diff suppressed because it is too large Load Diff

551
.CondaPkg/env/Lib/idlelib/debugger.py vendored Normal file
View File

@@ -0,0 +1,551 @@
import bdb
import os
from tkinter import *
from tkinter.ttk import Frame, Scrollbar
from idlelib import macosx
from idlelib.scrolledlist import ScrolledList
from idlelib.window import ListedToplevel
class Idb(bdb.Bdb):
def __init__(self, gui):
self.gui = gui # An instance of Debugger or proxy of remote.
bdb.Bdb.__init__(self)
def user_line(self, frame):
if self.in_rpc_code(frame):
self.set_step()
return
message = self.__frame2message(frame)
try:
self.gui.interaction(message, frame)
except TclError: # When closing debugger window with [x] in 3.x
pass
def user_exception(self, frame, info):
if self.in_rpc_code(frame):
self.set_step()
return
message = self.__frame2message(frame)
self.gui.interaction(message, frame, info)
def in_rpc_code(self, frame):
if frame.f_code.co_filename.count('rpc.py'):
return True
else:
prev_frame = frame.f_back
prev_name = prev_frame.f_code.co_filename
if 'idlelib' in prev_name and 'debugger' in prev_name:
# catch both idlelib/debugger.py and idlelib/debugger_r.py
# on both Posix and Windows
return False
return self.in_rpc_code(prev_frame)
def __frame2message(self, frame):
code = frame.f_code
filename = code.co_filename
lineno = frame.f_lineno
basename = os.path.basename(filename)
message = f"{basename}:{lineno}"
if code.co_name != "?":
message = f"{message}: {code.co_name}()"
return message
class Debugger:
vstack = vsource = vlocals = vglobals = None
def __init__(self, pyshell, idb=None):
if idb is None:
idb = Idb(self)
self.pyshell = pyshell
self.idb = idb # If passed, a proxy of remote instance.
self.frame = None
self.make_gui()
self.interacting = 0
self.nesting_level = 0
def run(self, *args):
# Deal with the scenario where we've already got a program running
# in the debugger and we want to start another. If that is the case,
# our second 'run' was invoked from an event dispatched not from
# the main event loop, but from the nested event loop in 'interaction'
# below. So our stack looks something like this:
# outer main event loop
# run()
# <running program with traces>
# callback to debugger's interaction()
# nested event loop
# run() for second command
#
# This kind of nesting of event loops causes all kinds of problems
# (see e.g. issue #24455) especially when dealing with running as a
# subprocess, where there's all kinds of extra stuff happening in
# there - insert a traceback.print_stack() to check it out.
#
# By this point, we've already called restart_subprocess() in
# ScriptBinding. However, we also need to unwind the stack back to
# that outer event loop. To accomplish this, we:
# - return immediately from the nested run()
# - abort_loop ensures the nested event loop will terminate
# - the debugger's interaction routine completes normally
# - the restart_subprocess() will have taken care of stopping
# the running program, which will also let the outer run complete
#
# That leaves us back at the outer main event loop, at which point our
# after event can fire, and we'll come back to this routine with a
# clean stack.
if self.nesting_level > 0:
self.abort_loop()
self.root.after(100, lambda: self.run(*args))
return
try:
self.interacting = 1
return self.idb.run(*args)
finally:
self.interacting = 0
def close(self, event=None):
try:
self.quit()
except Exception:
pass
if self.interacting:
self.top.bell()
return
if self.stackviewer:
self.stackviewer.close(); self.stackviewer = None
# Clean up pyshell if user clicked debugger control close widget.
# (Causes a harmless extra cycle through close_debugger() if user
# toggled debugger from pyshell Debug menu)
self.pyshell.close_debugger()
# Now close the debugger control window....
self.top.destroy()
def make_gui(self):
pyshell = self.pyshell
self.flist = pyshell.flist
self.root = root = pyshell.root
self.top = top = ListedToplevel(root)
self.top.wm_title("Debug Control")
self.top.wm_iconname("Debug")
top.wm_protocol("WM_DELETE_WINDOW", self.close)
self.top.bind("<Escape>", self.close)
#
self.bframe = bframe = Frame(top)
self.bframe.pack(anchor="w")
self.buttons = bl = []
#
self.bcont = b = Button(bframe, text="Go", command=self.cont)
bl.append(b)
self.bstep = b = Button(bframe, text="Step", command=self.step)
bl.append(b)
self.bnext = b = Button(bframe, text="Over", command=self.next)
bl.append(b)
self.bret = b = Button(bframe, text="Out", command=self.ret)
bl.append(b)
self.bret = b = Button(bframe, text="Quit", command=self.quit)
bl.append(b)
#
for b in bl:
b.configure(state="disabled")
b.pack(side="left")
#
self.cframe = cframe = Frame(bframe)
self.cframe.pack(side="left")
#
if not self.vstack:
self.__class__.vstack = BooleanVar(top)
self.vstack.set(1)
self.bstack = Checkbutton(cframe,
text="Stack", command=self.show_stack, variable=self.vstack)
self.bstack.grid(row=0, column=0)
if not self.vsource:
self.__class__.vsource = BooleanVar(top)
self.bsource = Checkbutton(cframe,
text="Source", command=self.show_source, variable=self.vsource)
self.bsource.grid(row=0, column=1)
if not self.vlocals:
self.__class__.vlocals = BooleanVar(top)
self.vlocals.set(1)
self.blocals = Checkbutton(cframe,
text="Locals", command=self.show_locals, variable=self.vlocals)
self.blocals.grid(row=1, column=0)
if not self.vglobals:
self.__class__.vglobals = BooleanVar(top)
self.bglobals = Checkbutton(cframe,
text="Globals", command=self.show_globals, variable=self.vglobals)
self.bglobals.grid(row=1, column=1)
#
self.status = Label(top, anchor="w")
self.status.pack(anchor="w")
self.error = Label(top, anchor="w")
self.error.pack(anchor="w", fill="x")
self.errorbg = self.error.cget("background")
#
self.fstack = Frame(top, height=1)
self.fstack.pack(expand=1, fill="both")
self.flocals = Frame(top)
self.flocals.pack(expand=1, fill="both")
self.fglobals = Frame(top, height=1)
self.fglobals.pack(expand=1, fill="both")
#
if self.vstack.get():
self.show_stack()
if self.vlocals.get():
self.show_locals()
if self.vglobals.get():
self.show_globals()
def interaction(self, message, frame, info=None):
self.frame = frame
self.status.configure(text=message)
#
if info:
type, value, tb = info
try:
m1 = type.__name__
except AttributeError:
m1 = "%s" % str(type)
if value is not None:
try:
# TODO redo entire section, tries not needed.
m1 = f"{m1}: {value}"
except:
pass
bg = "yellow"
else:
m1 = ""
tb = None
bg = self.errorbg
self.error.configure(text=m1, background=bg)
#
sv = self.stackviewer
if sv:
stack, i = self.idb.get_stack(self.frame, tb)
sv.load_stack(stack, i)
#
self.show_variables(1)
#
if self.vsource.get():
self.sync_source_line()
#
for b in self.buttons:
b.configure(state="normal")
#
self.top.wakeup()
# Nested main loop: Tkinter's main loop is not reentrant, so use
# Tcl's vwait facility, which reenters the event loop until an
# event handler sets the variable we're waiting on
self.nesting_level += 1
self.root.tk.call('vwait', '::idledebugwait')
self.nesting_level -= 1
#
for b in self.buttons:
b.configure(state="disabled")
self.status.configure(text="")
self.error.configure(text="", background=self.errorbg)
self.frame = None
def sync_source_line(self):
frame = self.frame
if not frame:
return
filename, lineno = self.__frame2fileline(frame)
if filename[:1] + filename[-1:] != "<>" and os.path.exists(filename):
self.flist.gotofileline(filename, lineno)
def __frame2fileline(self, frame):
code = frame.f_code
filename = code.co_filename
lineno = frame.f_lineno
return filename, lineno
def cont(self):
self.idb.set_continue()
self.abort_loop()
def step(self):
self.idb.set_step()
self.abort_loop()
def next(self):
self.idb.set_next(self.frame)
self.abort_loop()
def ret(self):
self.idb.set_return(self.frame)
self.abort_loop()
def quit(self):
self.idb.set_quit()
self.abort_loop()
def abort_loop(self):
self.root.tk.call('set', '::idledebugwait', '1')
stackviewer = None
def show_stack(self):
if not self.stackviewer and self.vstack.get():
self.stackviewer = sv = StackViewer(self.fstack, self.flist, self)
if self.frame:
stack, i = self.idb.get_stack(self.frame, None)
sv.load_stack(stack, i)
else:
sv = self.stackviewer
if sv and not self.vstack.get():
self.stackviewer = None
sv.close()
self.fstack['height'] = 1
def show_source(self):
if self.vsource.get():
self.sync_source_line()
def show_frame(self, stackitem):
self.frame = stackitem[0] # lineno is stackitem[1]
self.show_variables()
localsviewer = None
globalsviewer = None
def show_locals(self):
lv = self.localsviewer
if self.vlocals.get():
if not lv:
self.localsviewer = NamespaceViewer(self.flocals, "Locals")
else:
if lv:
self.localsviewer = None
lv.close()
self.flocals['height'] = 1
self.show_variables()
def show_globals(self):
gv = self.globalsviewer
if self.vglobals.get():
if not gv:
self.globalsviewer = NamespaceViewer(self.fglobals, "Globals")
else:
if gv:
self.globalsviewer = None
gv.close()
self.fglobals['height'] = 1
self.show_variables()
def show_variables(self, force=0):
lv = self.localsviewer
gv = self.globalsviewer
frame = self.frame
if not frame:
ldict = gdict = None
else:
ldict = frame.f_locals
gdict = frame.f_globals
if lv and gv and ldict is gdict:
ldict = None
if lv:
lv.load_dict(ldict, force, self.pyshell.interp.rpcclt)
if gv:
gv.load_dict(gdict, force, self.pyshell.interp.rpcclt)
def set_breakpoint_here(self, filename, lineno):
self.idb.set_break(filename, lineno)
def clear_breakpoint_here(self, filename, lineno):
self.idb.clear_break(filename, lineno)
def clear_file_breaks(self, filename):
self.idb.clear_all_file_breaks(filename)
def load_breakpoints(self):
"Load PyShellEditorWindow breakpoints into subprocess debugger"
for editwin in self.pyshell.flist.inversedict:
filename = editwin.io.filename
try:
for lineno in editwin.breakpoints:
self.set_breakpoint_here(filename, lineno)
except AttributeError:
continue
class StackViewer(ScrolledList):
def __init__(self, master, flist, gui):
if macosx.isAquaTk():
# At least on with the stock AquaTk version on OSX 10.4 you'll
# get a shaking GUI that eventually kills IDLE if the width
# argument is specified.
ScrolledList.__init__(self, master)
else:
ScrolledList.__init__(self, master, width=80)
self.flist = flist
self.gui = gui
self.stack = []
def load_stack(self, stack, index=None):
self.stack = stack
self.clear()
for i in range(len(stack)):
frame, lineno = stack[i]
try:
modname = frame.f_globals["__name__"]
except:
modname = "?"
code = frame.f_code
filename = code.co_filename
funcname = code.co_name
import linecache
sourceline = linecache.getline(filename, lineno)
sourceline = sourceline.strip()
if funcname in ("?", "", None):
item = "%s, line %d: %s" % (modname, lineno, sourceline)
else:
item = "%s.%s(), line %d: %s" % (modname, funcname,
lineno, sourceline)
if i == index:
item = "> " + item
self.append(item)
if index is not None:
self.select(index)
def popup_event(self, event):
"override base method"
if self.stack:
return ScrolledList.popup_event(self, event)
def fill_menu(self):
"override base method"
menu = self.menu
menu.add_command(label="Go to source line",
command=self.goto_source_line)
menu.add_command(label="Show stack frame",
command=self.show_stack_frame)
def on_select(self, index):
"override base method"
if 0 <= index < len(self.stack):
self.gui.show_frame(self.stack[index])
def on_double(self, index):
"override base method"
self.show_source(index)
def goto_source_line(self):
index = self.listbox.index("active")
self.show_source(index)
def show_stack_frame(self):
index = self.listbox.index("active")
if 0 <= index < len(self.stack):
self.gui.show_frame(self.stack[index])
def show_source(self, index):
if not (0 <= index < len(self.stack)):
return
frame, lineno = self.stack[index]
code = frame.f_code
filename = code.co_filename
if os.path.isfile(filename):
edit = self.flist.open(filename)
if edit:
edit.gotoline(lineno)
class NamespaceViewer:
def __init__(self, master, title, dict=None):
width = 0
height = 40
if dict:
height = 20*len(dict) # XXX 20 == observed height of Entry widget
self.master = master
self.title = title
import reprlib
self.repr = reprlib.Repr()
self.repr.maxstring = 60
self.repr.maxother = 60
self.frame = frame = Frame(master)
self.frame.pack(expand=1, fill="both")
self.label = Label(frame, text=title, borderwidth=2, relief="groove")
self.label.pack(fill="x")
self.vbar = vbar = Scrollbar(frame, name="vbar")
vbar.pack(side="right", fill="y")
self.canvas = canvas = Canvas(frame,
height=min(300, max(40, height)),
scrollregion=(0, 0, width, height))
canvas.pack(side="left", fill="both", expand=1)
vbar["command"] = canvas.yview
canvas["yscrollcommand"] = vbar.set
self.subframe = subframe = Frame(canvas)
self.sfid = canvas.create_window(0, 0, window=subframe, anchor="nw")
self.load_dict(dict)
dict = -1
def load_dict(self, dict, force=0, rpc_client=None):
if dict is self.dict and not force:
return
subframe = self.subframe
frame = self.frame
for c in list(subframe.children.values()):
c.destroy()
self.dict = None
if not dict:
l = Label(subframe, text="None")
l.grid(row=0, column=0)
else:
#names = sorted(dict)
###
# Because of (temporary) limitations on the dict_keys type (not yet
# public or pickleable), have the subprocess to send a list of
# keys, not a dict_keys object. sorted() will take a dict_keys
# (no subprocess) or a list.
#
# There is also an obscure bug in sorted(dict) where the
# interpreter gets into a loop requesting non-existing dict[0],
# dict[1], dict[2], etc from the debugger_r.DictProxy.
###
keys_list = dict.keys()
names = sorted(keys_list)
###
row = 0
for name in names:
value = dict[name]
svalue = self.repr.repr(value) # repr(value)
# Strip extra quotes caused by calling repr on the (already)
# repr'd value sent across the RPC interface:
if rpc_client:
svalue = svalue[1:-1]
l = Label(subframe, text=name)
l.grid(row=row, column=0, sticky="nw")
l = Entry(subframe, width=0, borderwidth=0)
l.insert(0, svalue)
l.grid(row=row, column=1, sticky="nw")
row = row+1
self.dict = dict
# XXX Could we use a <Configure> callback for the following?
subframe.update_idletasks() # Alas!
width = subframe.winfo_reqwidth()
height = subframe.winfo_reqheight()
canvas = self.canvas
self.canvas["scrollregion"] = (0, 0, width, height)
if height > 300:
canvas["height"] = 300
frame.pack(expand=1)
else:
canvas["height"] = height
frame.pack(expand=0)
def close(self):
self.frame.destroy()
if __name__ == "__main__":
from unittest import main
main('idlelib.idle_test.test_debugger', verbosity=2, exit=False)
# TODO: htest?

Some files were not shown because too many files have changed in this diff Show More